summaryrefslogtreecommitdiffstats
path: root/plugin
diff options
context:
space:
mode:
Diffstat (limited to 'plugin')
-rw-r--r--plugin/audit_null/CMakeLists.txt17
-rw-r--r--plugin/audit_null/audit_null.c207
-rw-r--r--plugin/auth_dialog/CMakeLists.txt20
-rw-r--r--plugin/auth_dialog/dialog.c191
-rw-r--r--plugin/auth_ed25519/CMakeLists.txt36
-rw-r--r--plugin/auth_ed25519/README27
-rw-r--r--plugin/auth_ed25519/client_ed25519.c68
-rw-r--r--plugin/auth_ed25519/common.h23
-rw-r--r--plugin/auth_ed25519/crypto_hash_sha512.h2
-rw-r--r--plugin/auth_ed25519/crypto_int32.h5
-rw-r--r--plugin/auth_ed25519/crypto_int64.h5
-rw-r--r--plugin/auth_ed25519/crypto_sign.h13
-rw-r--r--plugin/auth_ed25519/crypto_uint32.h5
-rw-r--r--plugin/auth_ed25519/crypto_uint64.h5
-rw-r--r--plugin/auth_ed25519/crypto_verify.h1
-rw-r--r--plugin/auth_ed25519/crypto_verify_32.h2
-rw-r--r--plugin/auth_ed25519/ed25519-t.c55
-rw-r--r--plugin/auth_ed25519/ref10/api.h3
-rw-r--r--plugin/auth_ed25519/ref10/base.h1344
-rw-r--r--plugin/auth_ed25519/ref10/base2.h40
-rw-r--r--plugin/auth_ed25519/ref10/d.h1
-rw-r--r--plugin/auth_ed25519/ref10/d2.h1
-rw-r--r--plugin/auth_ed25519/ref10/fe.h56
-rw-r--r--plugin/auth_ed25519/ref10/fe_0.c19
-rw-r--r--plugin/auth_ed25519/ref10/fe_1.c19
-rw-r--r--plugin/auth_ed25519/ref10/fe_add.c57
-rw-r--r--plugin/auth_ed25519/ref10/fe_cmov.c63
-rw-r--r--plugin/auth_ed25519/ref10/fe_copy.c29
-rw-r--r--plugin/auth_ed25519/ref10/fe_frombytes.c73
-rw-r--r--plugin/auth_ed25519/ref10/fe_invert.c14
-rw-r--r--plugin/auth_ed25519/ref10/fe_isnegative.c16
-rw-r--r--plugin/auth_ed25519/ref10/fe_isnonzero.c19
-rw-r--r--plugin/auth_ed25519/ref10/fe_mul.c253
-rw-r--r--plugin/auth_ed25519/ref10/fe_neg.c45
-rw-r--r--plugin/auth_ed25519/ref10/fe_pow22523.c13
-rw-r--r--plugin/auth_ed25519/ref10/fe_sq.c149
-rw-r--r--plugin/auth_ed25519/ref10/fe_sq2.c160
-rw-r--r--plugin/auth_ed25519/ref10/fe_sub.c57
-rw-r--r--plugin/auth_ed25519/ref10/fe_tobytes.c119
-rw-r--r--plugin/auth_ed25519/ref10/ge.h95
-rw-r--r--plugin/auth_ed25519/ref10/ge_add.c11
-rw-r--r--plugin/auth_ed25519/ref10/ge_add.h97
-rw-r--r--plugin/auth_ed25519/ref10/ge_double_scalarmult.c96
-rw-r--r--plugin/auth_ed25519/ref10/ge_frombytes.c50
-rw-r--r--plugin/auth_ed25519/ref10/ge_madd.c11
-rw-r--r--plugin/auth_ed25519/ref10/ge_madd.h88
-rw-r--r--plugin/auth_ed25519/ref10/ge_msub.c11
-rw-r--r--plugin/auth_ed25519/ref10/ge_msub.h88
-rw-r--r--plugin/auth_ed25519/ref10/ge_p1p1_to_p2.c12
-rw-r--r--plugin/auth_ed25519/ref10/ge_p1p1_to_p3.c13
-rw-r--r--plugin/auth_ed25519/ref10/ge_p2_0.c8
-rw-r--r--plugin/auth_ed25519/ref10/ge_p2_dbl.c11
-rw-r--r--plugin/auth_ed25519/ref10/ge_p2_dbl.h73
-rw-r--r--plugin/auth_ed25519/ref10/ge_p3_0.c9
-rw-r--r--plugin/auth_ed25519/ref10/ge_p3_dbl.c12
-rw-r--r--plugin/auth_ed25519/ref10/ge_p3_to_cached.c17
-rw-r--r--plugin/auth_ed25519/ref10/ge_p3_to_p2.c12
-rw-r--r--plugin/auth_ed25519/ref10/ge_p3_tobytes.c14
-rw-r--r--plugin/auth_ed25519/ref10/ge_precomp_0.c8
-rw-r--r--plugin/auth_ed25519/ref10/ge_scalarmult_base.c105
-rw-r--r--plugin/auth_ed25519/ref10/ge_sub.c11
-rw-r--r--plugin/auth_ed25519/ref10/ge_sub.h97
-rw-r--r--plugin/auth_ed25519/ref10/ge_tobytes.c14
-rw-r--r--plugin/auth_ed25519/ref10/keypair.c23
-rw-r--r--plugin/auth_ed25519/ref10/open.c36
-rw-r--r--plugin/auth_ed25519/ref10/pow22523.h160
-rw-r--r--plugin/auth_ed25519/ref10/pow225521.h160
-rw-r--r--plugin/auth_ed25519/ref10/sc.h15
-rw-r--r--plugin/auth_ed25519/ref10/sc_muladd.c368
-rw-r--r--plugin/auth_ed25519/ref10/sc_reduce.c275
-rw-r--r--plugin/auth_ed25519/ref10/sign.c39
-rw-r--r--plugin/auth_ed25519/ref10/sqrtm1.h1
-rw-r--r--plugin/auth_ed25519/ref10/verify.c40
-rw-r--r--plugin/auth_ed25519/server_ed25519.c171
-rw-r--r--plugin/auth_examples/CMakeLists.txt36
-rw-r--r--plugin/auth_examples/auth_0x0100.c91
-rw-r--r--plugin/auth_examples/clear_password_client.c47
-rw-r--r--plugin/auth_examples/dialog_examples.c158
-rw-r--r--plugin/auth_examples/qa_auth_client.c117
-rw-r--r--plugin/auth_examples/qa_auth_interface.c254
-rw-r--r--plugin/auth_examples/qa_auth_server.c79
-rw-r--r--plugin/auth_examples/test_plugin.c234
-rw-r--r--plugin/auth_gssapi/CMakeLists.txt54
-rw-r--r--plugin/auth_gssapi/README.md129
-rw-r--r--plugin/auth_gssapi/client_plugin.cc112
-rw-r--r--plugin/auth_gssapi/cmake/FindGSSAPI.cmake102
-rw-r--r--plugin/auth_gssapi/common.h4
-rw-r--r--plugin/auth_gssapi/gssapi_client.cc127
-rw-r--r--plugin/auth_gssapi/gssapi_errmsg.cc80
-rw-r--r--plugin/auth_gssapi/gssapi_errmsg.h29
-rw-r--r--plugin/auth_gssapi/gssapi_server.cc270
-rw-r--r--plugin/auth_gssapi/mysql-test/auth_gssapi/basic.result26
-rw-r--r--plugin/auth_gssapi/mysql-test/auth_gssapi/basic.test46
-rw-r--r--plugin/auth_gssapi/mysql-test/auth_gssapi/multiauth.result34
-rw-r--r--plugin/auth_gssapi/mysql-test/auth_gssapi/multiauth.test36
-rw-r--r--plugin/auth_gssapi/mysql-test/auth_gssapi/suite.opt1
-rw-r--r--plugin/auth_gssapi/mysql-test/auth_gssapi/suite.pm49
-rw-r--r--plugin/auth_gssapi/server_plugin.cc165
-rw-r--r--plugin/auth_gssapi/server_plugin.h51
-rw-r--r--plugin/auth_gssapi/sspi.h38
-rw-r--r--plugin/auth_gssapi/sspi_client.cc183
-rw-r--r--plugin/auth_gssapi/sspi_errmsg.cc150
-rw-r--r--plugin/auth_gssapi/sspi_server.cc330
-rw-r--r--plugin/auth_pam/CMakeLists.txt61
-rw-r--r--plugin/auth_pam/auth_pam.c254
-rw-r--r--plugin/auth_pam/auth_pam_base.c179
-rw-r--r--plugin/auth_pam/auth_pam_common.c56
-rw-r--r--plugin/auth_pam/auth_pam_tool.c120
-rw-r--r--plugin/auth_pam/auth_pam_tool.h81
-rw-r--r--plugin/auth_pam/auth_pam_v1.c86
-rw-r--r--plugin/auth_pam/config.h.cmake5
-rw-r--r--plugin/auth_pam/mapper/pam_user_map.c277
-rw-r--r--plugin/auth_pam/mapper/user_map.conf13
-rw-r--r--plugin/auth_pam/testing/CMakeLists.txt15
-rw-r--r--plugin/auth_pam/testing/mariadb_mtr.conf4
-rw-r--r--plugin/auth_pam/testing/pam_mariadb_mtr.c83
-rw-r--r--plugin/auth_pipe/CMakeLists.txt3
-rw-r--r--plugin/auth_pipe/auth_pipe.c94
-rw-r--r--plugin/auth_socket/CMakeLists.txt110
-rw-r--r--plugin/auth_socket/auth_socket.c149
-rw-r--r--plugin/aws_key_management/CMakeLists.txt17
-rw-r--r--plugin/aws_key_management/aws_key_management_plugin.cc768
-rw-r--r--plugin/cracklib_password_check/CMakeLists.txt13
-rw-r--r--plugin/cracklib_password_check/cracklib_password_check.c83
-rw-r--r--plugin/daemon_example/AUTHORS1
-rw-r--r--plugin/daemon_example/CMakeLists.txt20
-rw-r--r--plugin/daemon_example/ChangeLog2
-rw-r--r--plugin/daemon_example/NEWS2
-rw-r--r--plugin/daemon_example/README8
-rw-r--r--plugin/daemon_example/daemon_example.cc214
-rw-r--r--plugin/daemon_example/daemon_example.ini9
-rw-r--r--plugin/debug_key_management/CMakeLists.txt2
-rw-r--r--plugin/debug_key_management/debug_key_management_plugin.cc100
-rw-r--r--plugin/disks/CMakeLists.txt5
-rw-r--r--plugin/disks/README.txt86
-rw-r--r--plugin/disks/information_schema_disks.cc164
-rw-r--r--plugin/disks/mysql-test/disks/disks.result12
-rw-r--r--plugin/disks/mysql-test/disks/disks.test2
-rw-r--r--plugin/disks/mysql-test/disks/disks_notembedded.result22
-rw-r--r--plugin/disks/mysql-test/disks/disks_notembedded.test25
-rw-r--r--plugin/disks/mysql-test/disks/suite.opt1
-rw-r--r--plugin/disks/mysql-test/disks/suite.pm10
-rw-r--r--plugin/example_key_management/CMakeLists.txt2
-rw-r--r--plugin/example_key_management/example_key_management_plugin.cc170
-rw-r--r--plugin/feedback/CMakeLists.txt23
-rw-r--r--plugin/feedback/feedback.cc428
-rw-r--r--plugin/feedback/feedback.h79
-rw-r--r--plugin/feedback/sender_thread.cc298
-rw-r--r--plugin/feedback/url_base.cc96
-rw-r--r--plugin/feedback/url_http.cc341
-rw-r--r--plugin/feedback/utils.cc442
-rw-r--r--plugin/file_key_management/CMakeLists.txt4
-rw-r--r--plugin/file_key_management/file_key_management_plugin.cc207
-rw-r--r--plugin/file_key_management/parser.cc402
-rw-r--r--plugin/file_key_management/parser.h55
-rw-r--r--plugin/fulltext/AUTHORS1
-rw-r--r--plugin/fulltext/CMakeLists.txt17
-rw-r--r--plugin/fulltext/ChangeLog1
-rw-r--r--plugin/fulltext/NEWS1
-rw-r--r--plugin/fulltext/README1
-rw-r--r--plugin/fulltext/plugin_example.c273
-rw-r--r--plugin/func_test/CMakeLists.txt17
-rw-r--r--plugin/func_test/mysql-test/func_test/func_test.result28
-rw-r--r--plugin/func_test/mysql-test/func_test/func_test.test23
-rw-r--r--plugin/func_test/mysql-test/func_test/suite.opt1
-rw-r--r--plugin/func_test/mysql-test/func_test/suite.pm9
-rw-r--r--plugin/func_test/plugin.cc87
-rw-r--r--plugin/handler_socket/AUTHORS22
-rw-r--r--plugin/handler_socket/CMakeLists.txt39
-rw-r--r--plugin/handler_socket/ChangeLog19
-rw-r--r--plugin/handler_socket/Makefile.am88
-rw-r--r--plugin/handler_socket/README82
-rwxr-xr-xplugin/handler_socket/autogen.sh117
-rw-r--r--plugin/handler_socket/client/Makefile.am24
-rw-r--r--plugin/handler_socket/client/hsclient.cpp88
-rw-r--r--plugin/handler_socket/client/hslongrun.cpp1041
-rwxr-xr-xplugin/handler_socket/client/hspool_test.pl224
-rw-r--r--plugin/handler_socket/client/hstest.cpp1532
-rwxr-xr-xplugin/handler_socket/client/hstest.pl228
-rwxr-xr-xplugin/handler_socket/client/hstest_hs.sh4
-rwxr-xr-xplugin/handler_socket/client/hstest_hs_more50.sh4
-rwxr-xr-xplugin/handler_socket/client/hstest_md.sh7
-rwxr-xr-xplugin/handler_socket/client/hstest_my.sh3
-rwxr-xr-xplugin/handler_socket/client/hstest_my_more50.sh3
-rw-r--r--plugin/handler_socket/configure.ac144
-rw-r--r--plugin/handler_socket/docs-en/about-handlersocket.en.txt72
-rw-r--r--plugin/handler_socket/docs-en/configuration-options.en.txt99
-rw-r--r--plugin/handler_socket/docs-en/installation.en.txt92
-rw-r--r--plugin/handler_socket/docs-en/perl-client.en.txt134
-rw-r--r--plugin/handler_socket/docs-en/protocol.en.txt205
-rw-r--r--plugin/handler_socket/docs-ja/about-handlersocket.ja.txt51
-rw-r--r--plugin/handler_socket/docs-ja/installation.ja.txt88
-rw-r--r--plugin/handler_socket/docs-ja/perl-client.ja.txt126
-rw-r--r--plugin/handler_socket/docs-ja/protocol.ja.txt180
-rw-r--r--plugin/handler_socket/handlersocket/COPYRIGHT.txt27
-rw-r--r--plugin/handler_socket/handlersocket/Makefile.am8
-rw-r--r--plugin/handler_socket/handlersocket/Makefile.plain.template31
-rw-r--r--plugin/handler_socket/handlersocket/database.cpp1180
-rw-r--r--plugin/handler_socket/handlersocket/database.hpp142
-rw-r--r--plugin/handler_socket/handlersocket/handlersocket.cpp217
-rw-r--r--plugin/handler_socket/handlersocket/handlersocket.spec.template29
-rw-r--r--plugin/handler_socket/handlersocket/hstcpsvr.cpp147
-rw-r--r--plugin/handler_socket/handlersocket/hstcpsvr.hpp58
-rw-r--r--plugin/handler_socket/handlersocket/hstcpsvr_worker.cpp957
-rw-r--r--plugin/handler_socket/handlersocket/hstcpsvr_worker.hpp35
-rw-r--r--plugin/handler_socket/handlersocket/mysql_incl.hpp55
-rw-r--r--plugin/handler_socket/libhsclient/COPYRIGHT.txt27
-rw-r--r--plugin/handler_socket/libhsclient/Makefile.am12
-rw-r--r--plugin/handler_socket/libhsclient/Makefile.plain27
-rw-r--r--plugin/handler_socket/libhsclient/allocator.hpp64
-rw-r--r--plugin/handler_socket/libhsclient/auto_addrinfo.hpp52
-rw-r--r--plugin/handler_socket/libhsclient/auto_file.hpp69
-rw-r--r--plugin/handler_socket/libhsclient/auto_ptrcontainer.hpp67
-rw-r--r--plugin/handler_socket/libhsclient/config.cpp67
-rw-r--r--plugin/handler_socket/libhsclient/config.hpp32
-rw-r--r--plugin/handler_socket/libhsclient/escape.cpp127
-rw-r--r--plugin/handler_socket/libhsclient/escape.hpp66
-rw-r--r--plugin/handler_socket/libhsclient/fatal.cpp29
-rw-r--r--plugin/handler_socket/libhsclient/fatal.hpp21
-rw-r--r--plugin/handler_socket/libhsclient/hstcpcli.cpp442
-rw-r--r--plugin/handler_socket/libhsclient/hstcpcli.hpp62
-rw-r--r--plugin/handler_socket/libhsclient/libhsclient.spec.template39
-rw-r--r--plugin/handler_socket/libhsclient/mutex.hpp51
-rw-r--r--plugin/handler_socket/libhsclient/socket.cpp185
-rw-r--r--plugin/handler_socket/libhsclient/socket.hpp51
-rw-r--r--plugin/handler_socket/libhsclient/string_buffer.hpp118
-rw-r--r--plugin/handler_socket/libhsclient/string_ref.hpp63
-rw-r--r--plugin/handler_socket/libhsclient/string_util.cpp182
-rw-r--r--plugin/handler_socket/libhsclient/string_util.hpp53
-rw-r--r--plugin/handler_socket/libhsclient/thread.hpp84
-rw-r--r--plugin/handler_socket/libhsclient/util.hpp25
-rw-r--r--plugin/handler_socket/misc/microbench-hs.log130
-rw-r--r--plugin/handler_socket/misc/microbench-my.log125
-rw-r--r--plugin/handler_socket/perl-Net-HandlerSocket/COPYRIGHT.txt27
-rw-r--r--plugin/handler_socket/perl-Net-HandlerSocket/Changes6
-rw-r--r--plugin/handler_socket/perl-Net-HandlerSocket/HandlerSocket.xs634
-rw-r--r--plugin/handler_socket/perl-Net-HandlerSocket/MANIFEST8
-rw-r--r--plugin/handler_socket/perl-Net-HandlerSocket/Makefile.PL.in18
-rw-r--r--plugin/handler_socket/perl-Net-HandlerSocket/Makefile.PL.installed20
-rw-r--r--plugin/handler_socket/perl-Net-HandlerSocket/README30
-rw-r--r--plugin/handler_socket/perl-Net-HandlerSocket/lib/Net/HandlerSocket.pm68
-rwxr-xr-xplugin/handler_socket/perl-Net-HandlerSocket/lib/Net/HandlerSocket/Pool.pm362
-rw-r--r--plugin/handler_socket/perl-Net-HandlerSocket/perl-Net-HandlerSocket.spec.template127
-rw-r--r--plugin/handler_socket/perl-Net-HandlerSocket/ppport.h6375
-rw-r--r--plugin/handler_socket/perl-Net-HandlerSocket/t/HandlerSocket.t15
-rw-r--r--plugin/handler_socket/regtest/common/binary_my.cnf4
-rw-r--r--plugin/handler_socket/regtest/common/compat.sh29
-rw-r--r--plugin/handler_socket/regtest/common/hstest.pm66
-rwxr-xr-xplugin/handler_socket/regtest/test_01_lib/run.sh27
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test01.expected100
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test01.pl38
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test02.expected100
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test02.pl49
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test03.expected771
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test03.pl61
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test04.expectedbin0 -> 9589 bytes
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test04.pl63
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test05.expected771
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test05.pl59
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test06.expected644
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test06.pl90
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test07.expected304
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test07.pl98
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test08.expected2
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test08.pl48
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test09.expected12
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test09.pl67
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test10.expected771
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test10.pl93
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test11.expected37
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test11.pl112
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test12.expected273
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test12.pl134
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test13.expected92
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test13.pl92
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test14.expected144
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test14.pl80
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test15.expected764
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test15.pl114
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test16.expected66
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test16.pl88
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test17.expectedbin0 -> 4105 bytes
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test17.pl125
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test18.expected22
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test18.pl63
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test19.expected14894
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test19.pl190
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test20.expected2
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test20.pl33
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test21.expected11
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test21.pl58
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test22.expected9
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test22.pl61
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test23.expected101
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test23.pl53
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test24.expected2
-rw-r--r--plugin/handler_socket/regtest/test_01_lib/test24.pl35
-rw-r--r--plugin/locale_info/CMakeLists.txt4
-rw-r--r--plugin/locale_info/locale_info.cc121
-rw-r--r--plugin/metadata_lock_info/CMakeLists.txt3
-rw-r--r--plugin/metadata_lock_info/metadata_lock_info.cc144
-rw-r--r--plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/global_read_lock.result9
-rw-r--r--plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/table_metadata_lock.result13
-rw-r--r--plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/user_lock.result13
-rw-r--r--plugin/metadata_lock_info/mysql-test/metadata_lock_info/suite.opt2
-rw-r--r--plugin/metadata_lock_info/mysql-test/metadata_lock_info/suite.pm11
-rw-r--r--plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/global_read_lock.test6
-rw-r--r--plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/table_metadata_lock.test8
-rw-r--r--plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/user_lock.test5
-rw-r--r--plugin/qc_info/CMakeLists.txt4
-rw-r--r--plugin/qc_info/qc_info.cc316
-rw-r--r--plugin/query_response_time/CMakeLists.txt3
-rw-r--r--plugin/query_response_time/mysql-test/query_response_time/basic.result27
-rw-r--r--plugin/query_response_time/mysql-test/query_response_time/basic.test3
-rw-r--r--plugin/query_response_time/mysql-test/query_response_time/query_response_time-stored.inc36
-rw-r--r--plugin/query_response_time/mysql-test/query_response_time/query_response_time-stored.result392
-rw-r--r--plugin/query_response_time/mysql-test/query_response_time/query_response_time-stored.test44
-rw-r--r--plugin/query_response_time/mysql-test/query_response_time/query_response_time.inc41
-rw-r--r--plugin/query_response_time/mysql-test/query_response_time/query_response_time.result1003
-rw-r--r--plugin/query_response_time/mysql-test/query_response_time/query_response_time.test28
-rw-r--r--plugin/query_response_time/mysql-test/query_response_time/suite.opt1
-rw-r--r--plugin/query_response_time/mysql-test/query_response_time/suite.pm14
-rw-r--r--plugin/query_response_time/plugin.cc168
-rw-r--r--plugin/query_response_time/query_response_time.cc278
-rw-r--r--plugin/query_response_time/query_response_time.h67
-rw-r--r--plugin/server_audit/CMakeLists.txt18
-rw-r--r--plugin/server_audit/COPYING339
-rw-r--r--plugin/server_audit/plugin_audit_v4.h561
-rw-r--r--plugin/server_audit/server_audit.c3104
-rw-r--r--plugin/server_audit/test_audit_v4.c163
-rw-r--r--plugin/simple_password_check/CMakeLists.txt1
-rw-r--r--plugin/simple_password_check/simple_password_check.c117
-rw-r--r--plugin/sql_errlog/CMakeLists.txt16
-rw-r--r--plugin/sql_errlog/sql_errlog.c163
-rw-r--r--plugin/test_sql_service/CMakeLists.txt18
-rw-r--r--plugin/test_sql_service/COPYING339
-rw-r--r--plugin/test_sql_service/test_sql_service.c145
-rw-r--r--plugin/type_geom/CMakeLists.txt3
-rw-r--r--plugin/type_geom/plugin.cc254
-rw-r--r--plugin/type_inet/CMakeLists.txt18
-rw-r--r--plugin/type_inet/item_inetfunc.cc256
-rw-r--r--plugin/type_inet/item_inetfunc.h227
-rw-r--r--plugin/type_inet/mysql-test/type_inet/binlog_stm_type_inet6.result34
-rw-r--r--plugin/type_inet/mysql-test/type_inet/binlog_stm_type_inet6.test28
-rw-r--r--plugin/type_inet/mysql-test/type_inet/binlog_table_map_optional_metadata_type_inet6.result60
-rw-r--r--plugin/type_inet/mysql-test/type_inet/binlog_table_map_optional_metadata_type_inet6.test72
-rw-r--r--plugin/type_inet/mysql-test/type_inet/func_inet_plugin.result112
-rw-r--r--plugin/type_inet/mysql-test/type_inet/func_inet_plugin.test37
-rw-r--r--plugin/type_inet/mysql-test/type_inet/rpl_row_binary_to_inet6.result35
-rw-r--r--plugin/type_inet/mysql-test/type_inet/rpl_row_binary_to_inet6.test33
-rw-r--r--plugin/type_inet/mysql-test/type_inet/rpl_row_inet6_to_binary.result35
-rw-r--r--plugin/type_inet/mysql-test/type_inet/rpl_row_inet6_to_binary.test33
-rw-r--r--plugin/type_inet/mysql-test/type_inet/rpl_type_inet6.result17
-rw-r--r--plugin/type_inet/mysql-test/type_inet/rpl_type_inet6.test16
-rw-r--r--plugin/type_inet/mysql-test/type_inet/suite.pm9
-rw-r--r--plugin/type_inet/mysql-test/type_inet/type_inet6-debug.result18
-rw-r--r--plugin/type_inet/mysql-test/type_inet/type_inet6-debug.test14
-rw-r--r--plugin/type_inet/mysql-test/type_inet/type_inet6.result2161
-rw-r--r--plugin/type_inet/mysql-test/type_inet/type_inet6.test1588
-rw-r--r--plugin/type_inet/mysql-test/type_inet/type_inet6_csv.result70
-rw-r--r--plugin/type_inet/mysql-test/type_inet/type_inet6_csv.test51
-rw-r--r--plugin/type_inet/mysql-test/type_inet/type_inet6_engines.inc38
-rw-r--r--plugin/type_inet/mysql-test/type_inet/type_inet6_innodb.result92
-rw-r--r--plugin/type_inet/mysql-test/type_inet/type_inet6_innodb.test18
-rw-r--r--plugin/type_inet/mysql-test/type_inet/type_inet6_memory.result159
-rw-r--r--plugin/type_inet/mysql-test/type_inet/type_inet6_memory.test16
-rw-r--r--plugin/type_inet/mysql-test/type_inet/type_inet6_myisam.result92
-rw-r--r--plugin/type_inet/mysql-test/type_inet/type_inet6_myisam.test16
-rw-r--r--plugin/type_inet/mysql-test/type_inet/type_inet6_mysql.result39
-rw-r--r--plugin/type_inet/mysql-test/type_inet/type_inet6_mysql.test6
-rw-r--r--plugin/type_inet/mysql-test/type_inet/type_inet6_oracle.result29
-rw-r--r--plugin/type_inet/mysql-test/type_inet/type_inet6_oracle.test35
-rw-r--r--plugin/type_inet/mysql-test/type_inet/type_inet6_partition.result29
-rw-r--r--plugin/type_inet/mysql-test/type_inet/type_inet6_partition.test32
-rw-r--r--plugin/type_inet/mysql-test/type_inet/type_inet6_plugin.result31
-rw-r--r--plugin/type_inet/mysql-test/type_inet/type_inet6_plugin.test27
-rw-r--r--plugin/type_inet/mysql-test/type_inet/type_inet6_stat_tables.result31
-rw-r--r--plugin/type_inet/mysql-test/type_inet/type_inet6_stat_tables.test29
-rw-r--r--plugin/type_inet/plugin.cc311
-rw-r--r--plugin/type_inet/sql_type_inet.cc1642
-rw-r--r--plugin/type_inet/sql_type_inet.h1028
-rw-r--r--plugin/type_mysql_json/CMakeLists.txt18
-rw-r--r--plugin/type_mysql_json/mysql_json.cc515
-rw-r--r--plugin/type_mysql_json/mysql_json.h45
-rw-r--r--plugin/type_mysql_json/type.cc216
-rw-r--r--plugin/type_test/CMakeLists.txt17
-rw-r--r--plugin/type_test/mysql-test/type_test/suite.opt1
-rw-r--r--plugin/type_test/mysql-test/type_test/suite.pm10
-rw-r--r--plugin/type_test/mysql-test/type_test/type_test_double-debug.result35
-rw-r--r--plugin/type_test/mysql-test/type_test/type_test_double-debug.test32
-rw-r--r--plugin/type_test/mysql-test/type_test/type_test_double.result704
-rw-r--r--plugin/type_test/mysql-test/type_test/type_test_double.test530
-rw-r--r--plugin/type_test/mysql-test/type_test/type_test_int8-debug.result35
-rw-r--r--plugin/type_test/mysql-test/type_test/type_test_int8-debug.test32
-rw-r--r--plugin/type_test/mysql-test/type_test/type_test_int8.result683
-rw-r--r--plugin/type_test/mysql-test/type_test/type_test_int8.test518
-rw-r--r--plugin/type_test/mysql-test/type_test/type_test_mysql.result27
-rw-r--r--plugin/type_test/mysql-test/type_test/type_test_mysql.test10
-rw-r--r--plugin/type_test/plugin.cc322
-rw-r--r--plugin/user_variables/CMakeLists.txt2
-rw-r--r--plugin/user_variables/mysql-test/user_variables/basic.result63
-rw-r--r--plugin/user_variables/mysql-test/user_variables/basic.test24
-rw-r--r--plugin/user_variables/mysql-test/user_variables/suite.opt1
-rw-r--r--plugin/user_variables/mysql-test/user_variables/suite.pm14
-rw-r--r--plugin/user_variables/user_variables.cc142
-rw-r--r--plugin/userstat/CMakeLists.txt4
-rw-r--r--plugin/userstat/client_stats.cc103
-rw-r--r--plugin/userstat/index_stats.cc75
-rw-r--r--plugin/userstat/table_stats.cc78
-rw-r--r--plugin/userstat/user_stats.cc60
-rw-r--r--plugin/userstat/userstat.cc82
-rw-r--r--plugin/versioning/CMakeLists.txt17
-rw-r--r--plugin/versioning/versioning.cc206
-rw-r--r--plugin/win_auth_client/CMakeLists.txt34
-rw-r--r--plugin/win_auth_client/common.cc510
-rw-r--r--plugin/win_auth_client/common.h324
-rw-r--r--plugin/win_auth_client/handshake.cc289
-rw-r--r--plugin/win_auth_client/handshake.h181
-rw-r--r--plugin/win_auth_client/handshake_client.cc393
-rw-r--r--plugin/win_auth_client/log_client.cc65
-rw-r--r--plugin/win_auth_client/plugin_client.cc68
-rw-r--r--plugin/wsrep_info/CMakeLists.txt5
-rw-r--r--plugin/wsrep_info/mysql-test/wsrep_info/my.cnf35
-rw-r--r--plugin/wsrep_info/mysql-test/wsrep_info/r/plugin.result23
-rw-r--r--plugin/wsrep_info/mysql-test/wsrep_info/suite.opt1
-rw-r--r--plugin/wsrep_info/mysql-test/wsrep_info/suite.pm27
-rw-r--r--plugin/wsrep_info/mysql-test/wsrep_info/t/plugin.test23
-rw-r--r--plugin/wsrep_info/plugin.cc234
428 files changed, 77623 insertions, 0 deletions
diff --git a/plugin/audit_null/CMakeLists.txt b/plugin/audit_null/CMakeLists.txt
new file mode 100644
index 00000000..2d4b6e9b
--- /dev/null
+++ b/plugin/audit_null/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (c) 2006, 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
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
+
+MYSQL_ADD_PLUGIN(audit_null audit_null.c
+ MODULE_ONLY MODULE_OUTPUT_NAME "adt_null" COMPONENT Test)
diff --git a/plugin/audit_null/audit_null.c b/plugin/audit_null/audit_null.c
new file mode 100644
index 00000000..6e084c59
--- /dev/null
+++ b/plugin/audit_null/audit_null.c
@@ -0,0 +1,207 @@
+/* Copyright (c) 2006, 2011, Oracle and/or its affiliates.
+ Copyright (c) 2012, 2013, Monty Program Ab.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; version 2 of
+ the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include <stdio.h>
+#include <mysql/plugin.h>
+#include <mysql/plugin_audit.h>
+
+#if !defined(__attribute__) && (defined(__cplusplus) || !defined(__GNUC__) || __GNUC__ == 2 && __GNUC_MINOR__ < 8)
+#define __attribute__(A)
+#endif
+
+#ifdef _MSC_VER
+#define snprintf _snprintf
+#endif
+
+static volatile int ncalls; /* for SHOW STATUS, see below */
+static volatile int ncalls_general_log;
+static volatile int ncalls_general_error;
+static volatile int ncalls_general_result;
+
+FILE *f;
+
+/*
+ Initialize the plugin at server start or plugin installation.
+
+ SYNOPSIS
+ audit_null_plugin_init()
+
+ DESCRIPTION
+ Does nothing.
+
+ RETURN VALUE
+ 0 success
+ 1 failure (cannot happen)
+*/
+
+static int audit_null_plugin_init(void *arg __attribute__((unused)))
+{
+ ncalls= 0;
+ ncalls_general_log= 0;
+ ncalls_general_error= 0;
+ ncalls_general_result= 0;
+
+ f = fopen("audit_null_tables.log", "w");
+ if (!f)
+ return 1;
+
+ return 0;
+}
+
+
+/*
+ Terminate the plugin at server shutdown or plugin deinstallation.
+
+ SYNOPSIS
+ audit_null_plugin_deinit()
+ Does nothing.
+
+ RETURN VALUE
+ 0 success
+ 1 failure (cannot happen)
+
+*/
+
+static int audit_null_plugin_deinit(void *arg __attribute__((unused)))
+{
+ fclose(f);
+ return 0;
+}
+
+
+/*
+ Foo
+
+ SYNOPSIS
+ audit_null_notify()
+ thd connection context
+
+ DESCRIPTION
+*/
+
+static void audit_null_notify(MYSQL_THD thd __attribute__((unused)),
+ unsigned int event_class,
+ const void *event)
+{
+ /* prone to races, oh well */
+ ncalls++;
+ if (event_class == MYSQL_AUDIT_GENERAL_CLASS)
+ {
+ const struct mysql_event_general *event_general=
+ (const struct mysql_event_general *) event;
+ switch (event_general->event_subclass)
+ {
+ case MYSQL_AUDIT_GENERAL_LOG:
+ ncalls_general_log++;
+ fprintf(f, "%s\t>> %s\n", event_general->general_user,
+ event_general->general_query);
+ break;
+ case MYSQL_AUDIT_GENERAL_ERROR:
+ ncalls_general_error++;
+ break;
+ case MYSQL_AUDIT_GENERAL_RESULT:
+ ncalls_general_result++;
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ if (event_class == MYSQL_AUDIT_TABLE_CLASS)
+ {
+ const struct mysql_event_table *event_table=
+ (const struct mysql_event_table *) event;
+ const char *ip= event_table->ip ? event_table->ip : "";
+ const char *op= 0;
+ char buf[1024];
+
+ switch (event_table->event_subclass)
+ {
+ case MYSQL_AUDIT_TABLE_LOCK:
+ op= event_table->read_only ? "read" : "write";
+ break;
+ case MYSQL_AUDIT_TABLE_CREATE:
+ op= "create";
+ break;
+ case MYSQL_AUDIT_TABLE_DROP:
+ op= "drop";
+ break;
+ case MYSQL_AUDIT_TABLE_ALTER:
+ op= "alter";
+ break;
+ case MYSQL_AUDIT_TABLE_RENAME:
+ snprintf(buf, sizeof(buf), "rename to %s.%s",
+ event_table->new_database.str, event_table->new_table.str);
+ buf[sizeof(buf)-1]= 0;
+ op= buf;
+ break;
+ }
+
+ fprintf(f, "%s[%s] @ %s [%s]\t%s.%s : %s\n",
+ event_table->priv_user, event_table->user,
+ event_table->host, ip,
+ event_table->database.str, event_table->table.str, op);
+ }
+}
+
+
+/*
+ Plugin type-specific descriptor
+*/
+
+static struct st_mysql_audit audit_null_descriptor=
+{
+ MYSQL_AUDIT_INTERFACE_VERSION, NULL, audit_null_notify,
+ { MYSQL_AUDIT_GENERAL_CLASSMASK | MYSQL_AUDIT_TABLE_CLASSMASK }
+};
+
+/*
+ Plugin status variables for SHOW STATUS
+*/
+
+static struct st_mysql_show_var simple_status[]=
+{
+ { "called", (char *) &ncalls, SHOW_INT },
+ { "general_error", (char *) &ncalls_general_error, SHOW_INT },
+ { "general_log", (char *) &ncalls_general_log, SHOW_INT },
+ { "general_result", (char *) &ncalls_general_result, SHOW_INT },
+ { 0, 0, 0}
+};
+
+
+/*
+ Plugin library descriptor
+*/
+
+mysql_declare_plugin(audit_null)
+{
+ MYSQL_AUDIT_PLUGIN, /* type */
+ &audit_null_descriptor, /* descriptor */
+ "AUDIT_NULL", /* name */
+ "Oracle Corp", /* author */
+ "Simple NULL Audit", /* description */
+ PLUGIN_LICENSE_GPL,
+ audit_null_plugin_init, /* init function (when loaded) */
+ audit_null_plugin_deinit, /* deinit function (when unloaded) */
+ 0x0002, /* version */
+ simple_status, /* status variables */
+ NULL, /* system variables */
+ NULL,
+ 0,
+}
+mysql_declare_plugin_end;
+
diff --git a/plugin/auth_dialog/CMakeLists.txt b/plugin/auth_dialog/CMakeLists.txt
new file mode 100644
index 00000000..b5e1b2be
--- /dev/null
+++ b/plugin/auth_dialog/CMakeLists.txt
@@ -0,0 +1,20 @@
+# Copyright (c) 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 the Free Software Foundation; version 2 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
+
+# disabled in favor of libmariadb/plugins/auth/dialog.c
+#
+#MYSQL_ADD_PLUGIN(dialog dialog.c ${CMAKE_SOURCE_DIR}/libmysql/get_password.c
+# MODULE_ONLY CLIENT COMPONENT ClientPlugins)
diff --git a/plugin/auth_dialog/dialog.c b/plugin/auth_dialog/dialog.c
new file mode 100644
index 00000000..3ea1da22
--- /dev/null
+++ b/plugin/auth_dialog/dialog.c
@@ -0,0 +1,191 @@
+/* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab
+ Copyright (c) 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 the Free Software Foundation; version 2 of the
+ License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/**
+ @file
+
+ dialog client authentication plugin with examples
+
+ dialog is a general purpose client authentication plugin, it simply
+ asks the user the question, as provided by the server and reports
+ the answer back to the server. No encryption is involved,
+ the answers are sent in clear text.
+*/
+#define _GNU_SOURCE 1 /* for RTLD_DEFAULT */
+
+#include <my_global.h>
+#include <mysql/client_plugin.h>
+#include <mysql.h>
+#include <string.h>
+
+#if defined (_WIN32)
+# define RTLD_DEFAULT GetModuleHandle(NULL)
+#endif
+
+/*
+ This plugin performs a dialog with the user, asking questions and
+ reading answers. Depending on the client it may be desirable to do it
+ using GUI, or console, with or without curses, or read answers
+ from a smartcard, for example.
+
+ To support all this variety, the dialog plugin has a callback function
+ "authentication_dialog_ask". If the client has a function of this name
+ dialog plugin will use it for communication with the user. Otherwise
+ a default implementation will be used.
+*/
+static mysql_authentication_dialog_ask_t ask;
+
+static char *builtin_ask(MYSQL *mysql __attribute__((unused)),
+ int type __attribute__((unused)),
+ const char *prompt,
+ char *buf, int buf_len)
+{
+ fputs(prompt, stdout);
+ fputc(' ', stdout);
+
+ if (type == 2) /* password */
+ {
+ get_tty_password_buff("", buf, buf_len);
+ buf[buf_len-1]= 0;
+ }
+ else
+ {
+ if (!fgets(buf, buf_len-1, stdin))
+ buf[0]= 0;
+ else
+ {
+ int len= strlen(buf);
+ if (len && buf[len-1] == '\n')
+ buf[len-1]= 0;
+ }
+ }
+
+ return buf;
+}
+
+/**
+ The main function of the dialog plugin.
+
+ Read the prompt, ask the question, send the reply, repeat until
+ the server is satisfied.
+
+ @note
+ 1. this plugin shows how a client authentication plugin
+ may read a MySQL protocol OK packet internally - which is important
+ where a number of packets is not known in advance.
+ 2. the first byte of the prompt is special. it is not
+ shown to the user, but signals whether it is the last question
+ (prompt[0] & 1 == 1) or not last (prompt[0] & 1 == 0),
+ and whether the input is a password (not echoed).
+ 3. the prompt is expected to be sent zero-terminated
+*/
+static int perform_dialog(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
+{
+ unsigned char *pkt, cmd= 0;
+ int pkt_len, res;
+ char reply_buf[1024], *reply;
+ int first = 1;
+
+ do
+ {
+ /* read the prompt */
+ pkt_len= vio->read_packet(vio, &pkt);
+ if (pkt_len < 0)
+ return CR_ERROR;
+
+ if (pkt == 0 && first)
+ {
+ /*
+ in mysql_change_user() the client sends the first packet, so
+ the first vio->read_packet() does nothing (pkt == 0).
+
+ We send the "password", assuming the client knows what its doing.
+ (in other words, the dialog plugin should be only set as a default
+ authentication plugin on the client if the first question
+ asks for a password - which will be sent in clear text, by the way)
+ */
+ reply= mysql->passwd;
+ }
+ else
+ {
+ cmd= *pkt++;
+
+ /* is it MySQL protocol packet ? */
+ if (cmd == 0 || cmd == 254)
+ return CR_OK_HANDSHAKE_COMPLETE; /* yes. we're done */
+
+ /*
+ asking for a password in the first packet mean mysql->password, if it's set
+ otherwise we ask the user and read the reply
+ */
+ if ((cmd >> 1) == 2 && first && mysql->passwd[0])
+ reply= mysql->passwd;
+ else
+ reply= ask(mysql, cmd >> 1, (const char *) pkt,
+ reply_buf, sizeof(reply_buf));
+ if (!reply)
+ return CR_ERROR;
+ }
+ /* send the reply to the server */
+ res= vio->write_packet(vio, (const unsigned char *) reply,
+ strlen(reply)+1);
+
+ if (reply != mysql->passwd && reply != reply_buf)
+ free(reply);
+
+ if (res)
+ return CR_ERROR;
+
+ first= 0;
+
+ /* repeat unless it was the last question */
+ } while ((cmd & 1) != 1);
+
+ /* the job of reading the ok/error packet is left to the server */
+ return CR_OK;
+}
+
+/**
+ initialization function of the dialog plugin
+
+ Pick up the client's authentication_dialog_ask() function, if exists,
+ or fall back to the default implementation.
+*/
+
+static int init_dialog(char *unused1 __attribute__((unused)),
+ size_t unused2 __attribute__((unused)),
+ int unused3 __attribute__((unused)),
+ va_list unused4 __attribute__((unused)))
+{
+ void *sym= dlsym(RTLD_DEFAULT, "mysql_authentication_dialog_ask");
+ ask= sym ? (mysql_authentication_dialog_ask_t) sym : builtin_ask;
+ return 0;
+}
+
+mysql_declare_client_plugin(AUTHENTICATION)
+ "dialog",
+ "Sergei Golubchik",
+ "Dialog Client Authentication Plugin",
+ {0,1,0},
+ "GPL",
+ NULL,
+ init_dialog,
+ NULL,
+ NULL,
+ perform_dialog
+mysql_end_client_plugin;
+
diff --git a/plugin/auth_ed25519/CMakeLists.txt b/plugin/auth_ed25519/CMakeLists.txt
new file mode 100644
index 00000000..1033dc05
--- /dev/null
+++ b/plugin/auth_ed25519/CMakeLists.txt
@@ -0,0 +1,36 @@
+SET(REF10_SOURCES
+ ref10/fe_0.c ref10/fe_1.c ref10/fe_add.c ref10/fe_cmov.c ref10/fe_copy.c
+ ref10/fe_frombytes.c ref10/fe_invert.c ref10/fe_isnegative.c
+ ref10/fe_isnonzero.c ref10/fe_mul.c ref10/fe_neg.c ref10/fe_pow22523.c
+ ref10/fe_sq.c ref10/fe_sq2.c ref10/fe_sub.c ref10/fe_tobytes.c
+ ref10/ge_add.c ref10/ge_double_scalarmult.c ref10/ge_frombytes.c
+ ref10/ge_madd.c ref10/ge_msub.c ref10/ge_p1p1_to_p2.c
+ ref10/ge_p1p1_to_p3.c ref10/ge_p2_0.c ref10/ge_p2_dbl.c ref10/ge_p3_0.c
+ ref10/ge_p3_dbl.c ref10/ge_p3_to_cached.c ref10/ge_p3_to_p2.c
+ ref10/ge_p3_tobytes.c ref10/ge_precomp_0.c ref10/ge_scalarmult_base.c
+ ref10/ge_sub.c ref10/ge_tobytes.c ref10/keypair.c ref10/open.c
+ ref10/sc_muladd.c ref10/sc_reduce.c ref10/sign.c ref10/verify.c)
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+
+ADD_CONVENIENCE_LIBRARY(ref10 ${REF10_SOURCES})
+IF(MSVC)
+ # Silence conversion (integer truncantion) warnings from reference code
+ SET_SOURCE_FILES_PROPERTIES(${REF10_SOURCES} PROPERTY COMPILE_FLAGS "/wd4244 /wd4146")
+ENDIF()
+
+IF(CMAKE_C_COMPILER_ID MATCHES "GNU" AND CMAKE_C_COMPILER_VERSION LESS 11 AND CMAKE_C_COMPILER_VERSION GREATER 6)
+ SET_SOURCE_FILES_PROPERTIES(${REF10_SOURCES} PROPERTY COMPILE_FLAGS -fno-sanitize=shift)
+ENDIF()
+
+# server plugin *cannot* link with the library, it needs all sources to be
+# compiled with MYSQL_DYNAMIC_PLUGIN
+MYSQL_ADD_PLUGIN(auth_ed25519 server_ed25519.c ${REF10_SOURCES} MODULE_ONLY)
+
+# client plugin and unit test ed25519-t can use the library
+#MYSQL_ADD_PLUGIN(client_ed25519 client_ed25519.c MODULE_ONLY
+# CLIENT LINK_LIBRARIES ref10 mysys_ssl COMPONENT ClientPlugins)
+
+IF(WITH_UNIT_TESTS)
+ MY_ADD_TESTS(ed25519 LINK_LIBRARIES ref10 mysys_ssl)
+ENDIF()
diff --git a/plugin/auth_ed25519/README b/plugin/auth_ed25519/README
new file mode 100644
index 00000000..e65a33e6
--- /dev/null
+++ b/plugin/auth_ed25519/README
@@ -0,0 +1,27 @@
+This plugin uses public domain ed25519 code
+by Daniel J. Bernstein, Niels Duif, Tanja Lange, Peter Schwabe, Bo-Yin Yang.
+
+It is "ref10" implementation from the SUPERCOP:
+https://bench.cr.yp.to/supercop.html
+
+OpenSSH also uses ed25519 from SUPERCOP, but "ref" implementation.
+
+There are four ed25519 implementations in SUPERCOP, ref10 is faster then ref,
+and there are two that are even faster, written in amd64 assembler.
+Benchmarks are here: https://bench.cr.yp.to/impl-sign/ed25519.html
+
+==============================
+MariaDB changes:
+
+API functions were simplified to better fit our use case:
+* crypto_sign_open() does not return the verified message, only the
+ result of the verification (passed/failed)
+* no secret key is generated explicitly, user specified password is used
+ as a source of randomness instead (SHA512("user password")).
+* lengths are not returned, where they're known in advance
+ (e.g. from crypto_sign()).
+* crypto_sign() does not take the public key as an argument, but
+ generates it on the fly (we used to generate public key before
+ crypto_sign(), doing it internally avoids double work).
+
+See the changes done in this commit.
diff --git a/plugin/auth_ed25519/client_ed25519.c b/plugin/auth_ed25519/client_ed25519.c
new file mode 100644
index 00000000..5222da8c
--- /dev/null
+++ b/plugin/auth_ed25519/client_ed25519.c
@@ -0,0 +1,68 @@
+/*
+ Copyright (c) 2017, MariaDB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/************************** CLIENT *************************************/
+
+#include <stdlib.h>
+#include "common.h"
+#include <mysql/client_plugin.h>
+#include <errmsg.h>
+
+#if !defined(__attribute__) && !defined(__GNUC__)
+#define __attribute__(A)
+#endif
+
+static int do_auth(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
+{
+ unsigned char reply[CRYPTO_BYTES + NONCE_BYTES], *pkt;
+ int pkt_len;
+
+ /* read the nonce */
+ if ((pkt_len= vio->read_packet(vio, &pkt)) != NONCE_BYTES)
+ return CR_SERVER_HANDSHAKE_ERR;
+
+ /* sign the nonce */
+ crypto_sign(reply, pkt, NONCE_BYTES,
+ (unsigned char*)mysql->passwd, strlen(mysql->passwd));
+
+ /* send the signature */
+ if (vio->write_packet(vio, reply, CRYPTO_BYTES))
+ return CR_ERROR;
+
+ return CR_OK;
+}
+
+static int init_client(char *unused1 __attribute__((unused)),
+ size_t unused2 __attribute__((unused)),
+ int unused3 __attribute__((unused)),
+ va_list unused4 __attribute__((unused)))
+{
+ return 0;
+}
+
+mysql_declare_client_plugin(AUTHENTICATION)
+ "client_ed25519",
+ "Sergei Golubchik",
+ "Elliptic curve ED25519 based authentication",
+ {0,1,0},
+ "GPL",
+ NULL,
+ init_client,
+ NULL,
+ NULL,
+ do_auth,
+mysql_end_client_plugin;
+
diff --git a/plugin/auth_ed25519/common.h b/plugin/auth_ed25519/common.h
new file mode 100644
index 00000000..963a8afb
--- /dev/null
+++ b/plugin/auth_ed25519/common.h
@@ -0,0 +1,23 @@
+/*
+ Copyright (c) 2017, MariaDB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include <mysql.h>
+#include <string.h>
+
+#include "ref10/api.h"
+#include "crypto_sign.h"
+
+#define NONCE_BYTES 32
diff --git a/plugin/auth_ed25519/crypto_hash_sha512.h b/plugin/auth_ed25519/crypto_hash_sha512.h
new file mode 100644
index 00000000..a1be896f
--- /dev/null
+++ b/plugin/auth_ed25519/crypto_hash_sha512.h
@@ -0,0 +1,2 @@
+#include <mysql/service_sha2.h>
+#define crypto_hash_sha512(DST,SRC,SLEN) my_sha512(DST,(char*)(SRC),SLEN)
diff --git a/plugin/auth_ed25519/crypto_int32.h b/plugin/auth_ed25519/crypto_int32.h
new file mode 100644
index 00000000..642fca05
--- /dev/null
+++ b/plugin/auth_ed25519/crypto_int32.h
@@ -0,0 +1,5 @@
+#include <stdint.h>
+#include <sys/types.h>
+typedef int32_t crypto_int32;
+
+#define select ed25519_select
diff --git a/plugin/auth_ed25519/crypto_int64.h b/plugin/auth_ed25519/crypto_int64.h
new file mode 100644
index 00000000..a308e406
--- /dev/null
+++ b/plugin/auth_ed25519/crypto_int64.h
@@ -0,0 +1,5 @@
+#include <stdint.h>
+#include <sys/types.h>
+typedef int64_t crypto_int64;
+
+#define select ed25519_select
diff --git a/plugin/auth_ed25519/crypto_sign.h b/plugin/auth_ed25519/crypto_sign.h
new file mode 100644
index 00000000..e12a8c71
--- /dev/null
+++ b/plugin/auth_ed25519/crypto_sign.h
@@ -0,0 +1,13 @@
+int crypto_sign_keypair(
+ unsigned char *pk,
+ unsigned char *pw, unsigned long long pwlen
+);
+int crypto_sign(
+ unsigned char *sm,
+ const unsigned char *m, unsigned long long mlen,
+ const unsigned char *pw, unsigned long long pwlen
+);
+int crypto_sign_open(
+ unsigned char *sm, unsigned long long smlen,
+ const unsigned char *pk
+);
diff --git a/plugin/auth_ed25519/crypto_uint32.h b/plugin/auth_ed25519/crypto_uint32.h
new file mode 100644
index 00000000..ab2977ca
--- /dev/null
+++ b/plugin/auth_ed25519/crypto_uint32.h
@@ -0,0 +1,5 @@
+#include <stdint.h>
+#include <sys/types.h>
+typedef uint32_t crypto_uint32;
+
+#define select ed25519_select
diff --git a/plugin/auth_ed25519/crypto_uint64.h b/plugin/auth_ed25519/crypto_uint64.h
new file mode 100644
index 00000000..029c6819
--- /dev/null
+++ b/plugin/auth_ed25519/crypto_uint64.h
@@ -0,0 +1,5 @@
+#include <stdint.h>
+#include <sys/types.h>
+typedef uint64_t crypto_uint64;
+
+#define select ed25519_select
diff --git a/plugin/auth_ed25519/crypto_verify.h b/plugin/auth_ed25519/crypto_verify.h
new file mode 100644
index 00000000..33e11b1e
--- /dev/null
+++ b/plugin/auth_ed25519/crypto_verify.h
@@ -0,0 +1 @@
+int crypto_verify(const unsigned char *x,const unsigned char *y);
diff --git a/plugin/auth_ed25519/crypto_verify_32.h b/plugin/auth_ed25519/crypto_verify_32.h
new file mode 100644
index 00000000..d8235b75
--- /dev/null
+++ b/plugin/auth_ed25519/crypto_verify_32.h
@@ -0,0 +1,2 @@
+#define crypto_verify_32 crypto_verify
+int crypto_verify(const unsigned char *x,const unsigned char *y);
diff --git a/plugin/auth_ed25519/ed25519-t.c b/plugin/auth_ed25519/ed25519-t.c
new file mode 100644
index 00000000..4373e59a
--- /dev/null
+++ b/plugin/auth_ed25519/ed25519-t.c
@@ -0,0 +1,55 @@
+/*
+ Copyright (c) 2017, MariaDB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include <tap.h>
+#include <m_string.h>
+#include "common.h"
+
+int main()
+{
+ uchar pk[CRYPTO_PUBLICKEYBYTES];
+ uchar foobar_pk[CRYPTO_PUBLICKEYBYTES]= {170, 253, 166, 27, 161, 214, 10,
+ 236, 183, 217, 41, 91, 231, 24, 85, 225, 49, 210, 181, 236, 13, 207, 101,
+ 72, 53, 83, 219, 130, 79, 151, 0, 159};
+ uchar foobar_sign[CRYPTO_BYTES]= {232, 61, 201, 63, 67, 63, 51, 53, 86, 73,
+ 238, 35, 170, 117, 146, 214, 26, 17, 35, 9, 8, 132, 245, 141, 48, 99, 66,
+ 58, 36, 228, 48, 84, 115, 254, 187, 168, 88, 162, 249, 57, 35, 85, 79, 238,
+ 167, 106, 68, 117, 56, 135, 171, 47, 20, 14, 133, 79, 15, 229, 124, 160,
+ 176, 100, 138, 14};
+
+ uchar nonce[NONCE_BYTES];
+ uchar reply[NONCE_BYTES+CRYPTO_BYTES];
+ int r;
+
+ plan(4);
+
+ crypto_sign_keypair(pk, USTRING_WITH_LEN("foobar"));
+ ok(!memcmp(pk, foobar_pk, CRYPTO_PUBLICKEYBYTES), "foobar pk");
+
+ memset(nonce, 'A', sizeof(nonce));
+ crypto_sign(reply, nonce, sizeof(nonce), USTRING_WITH_LEN("foobar"));
+ ok(!memcmp(reply, foobar_sign, CRYPTO_BYTES), "foobar sign");
+
+ r= crypto_sign_open(reply, sizeof(reply), pk);
+ ok(!r, "good nonce");
+
+ crypto_sign(reply, nonce, sizeof(nonce), USTRING_WITH_LEN("foobar"));
+ reply[CRYPTO_BYTES + 10]='B';
+ r= crypto_sign_open(reply, sizeof(reply), pk);
+ ok(r, "bad nonce");
+
+ return exit_status();
+}
diff --git a/plugin/auth_ed25519/ref10/api.h b/plugin/auth_ed25519/ref10/api.h
new file mode 100644
index 00000000..9f1db7e5
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/api.h
@@ -0,0 +1,3 @@
+#define CRYPTO_PUBLICKEYBYTES 32
+#define CRYPTO_BYTES 64
+#define CRYPTO_DETERMINISTIC 1
diff --git a/plugin/auth_ed25519/ref10/base.h b/plugin/auth_ed25519/ref10/base.h
new file mode 100644
index 00000000..573bd8a0
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/base.h
@@ -0,0 +1,1344 @@
+{
+ {
+ { 25967493,-14356035,29566456,3660896,-12694345,4014787,27544626,-11754271,-6079156,2047605 },
+ { -12545711,934262,-2722910,3049990,-727428,9406986,12720692,5043384,19500929,-15469378 },
+ { -8738181,4489570,9688441,-14785194,10184609,-12363380,29287919,11864899,-24514362,-4438546 },
+ },
+ {
+ { -12815894,-12976347,-21581243,11784320,-25355658,-2750717,-11717903,-3814571,-358445,-10211303 },
+ { -21703237,6903825,27185491,6451973,-29577724,-9554005,-15616551,11189268,-26829678,-5319081 },
+ { 26966642,11152617,32442495,15396054,14353839,-12752335,-3128826,-9541118,-15472047,-4166697 },
+ },
+ {
+ { 15636291,-9688557,24204773,-7912398,616977,-16685262,27787600,-14772189,28944400,-1550024 },
+ { 16568933,4717097,-11556148,-1102322,15682896,-11807043,16354577,-11775962,7689662,11199574 },
+ { 30464156,-5976125,-11779434,-15670865,23220365,15915852,7512774,10017326,-17749093,-9920357 },
+ },
+ {
+ { -17036878,13921892,10945806,-6033431,27105052,-16084379,-28926210,15006023,3284568,-6276540 },
+ { 23599295,-8306047,-11193664,-7687416,13236774,10506355,7464579,9656445,13059162,10374397 },
+ { 7798556,16710257,3033922,2874086,28997861,2835604,32406664,-3839045,-641708,-101325 },
+ },
+ {
+ { 10861363,11473154,27284546,1981175,-30064349,12577861,32867885,14515107,-15438304,10819380 },
+ { 4708026,6336745,20377586,9066809,-11272109,6594696,-25653668,12483688,-12668491,5581306 },
+ { 19563160,16186464,-29386857,4097519,10237984,-4348115,28542350,13850243,-23678021,-15815942 },
+ },
+ {
+ { -15371964,-12862754,32573250,4720197,-26436522,5875511,-19188627,-15224819,-9818940,-12085777 },
+ { -8549212,109983,15149363,2178705,22900618,4543417,3044240,-15689887,1762328,14866737 },
+ { -18199695,-15951423,-10473290,1707278,-17185920,3916101,-28236412,3959421,27914454,4383652 },
+ },
+ {
+ { 5153746,9909285,1723747,-2777874,30523605,5516873,19480852,5230134,-23952439,-15175766 },
+ { -30269007,-3463509,7665486,10083793,28475525,1649722,20654025,16520125,30598449,7715701 },
+ { 28881845,14381568,9657904,3680757,-20181635,7843316,-31400660,1370708,29794553,-1409300 },
+ },
+ {
+ { 14499471,-2729599,-33191113,-4254652,28494862,14271267,30290735,10876454,-33154098,2381726 },
+ { -7195431,-2655363,-14730155,462251,-27724326,3941372,-6236617,3696005,-32300832,15351955 },
+ { 27431194,8222322,16448760,-3907995,-18707002,11938355,-32961401,-2970515,29551813,10109425 },
+ },
+},
+{
+ {
+ { -13657040,-13155431,-31283750,11777098,21447386,6519384,-2378284,-1627556,10092783,-4764171 },
+ { 27939166,14210322,4677035,16277044,-22964462,-12398139,-32508754,12005538,-17810127,12803510 },
+ { 17228999,-15661624,-1233527,300140,-1224870,-11714777,30364213,-9038194,18016357,4397660 },
+ },
+ {
+ { -10958843,-7690207,4776341,-14954238,27850028,-15602212,-26619106,14544525,-17477504,982639 },
+ { 29253598,15796703,-2863982,-9908884,10057023,3163536,7332899,-4120128,-21047696,9934963 },
+ { 5793303,16271923,-24131614,-10116404,29188560,1206517,-14747930,4559895,-30123922,-10897950 },
+ },
+ {
+ { -27643952,-11493006,16282657,-11036493,28414021,-15012264,24191034,4541697,-13338309,5500568 },
+ { 12650548,-1497113,9052871,11355358,-17680037,-8400164,-17430592,12264343,10874051,13524335 },
+ { 25556948,-3045990,714651,2510400,23394682,-10415330,33119038,5080568,-22528059,5376628 },
+ },
+ {
+ { -26088264,-4011052,-17013699,-3537628,-6726793,1920897,-22321305,-9447443,4535768,1569007 },
+ { -2255422,14606630,-21692440,-8039818,28430649,8775819,-30494562,3044290,31848280,12543772 },
+ { -22028579,2943893,-31857513,6777306,13784462,-4292203,-27377195,-2062731,7718482,14474653 },
+ },
+ {
+ { 2385315,2454213,-22631320,46603,-4437935,-15680415,656965,-7236665,24316168,-5253567 },
+ { 13741529,10911568,-33233417,-8603737,-20177830,-1033297,33040651,-13424532,-20729456,8321686 },
+ { 21060490,-2212744,15712757,-4336099,1639040,10656336,23845965,-11874838,-9984458,608372 },
+ },
+ {
+ { -13672732,-15087586,-10889693,-7557059,-6036909,11305547,1123968,-6780577,27229399,23887 },
+ { -23244140,-294205,-11744728,14712571,-29465699,-2029617,12797024,-6440308,-1633405,16678954 },
+ { -29500620,4770662,-16054387,14001338,7830047,9564805,-1508144,-4795045,-17169265,4904953 },
+ },
+ {
+ { 24059557,14617003,19037157,-15039908,19766093,-14906429,5169211,16191880,2128236,-4326833 },
+ { -16981152,4124966,-8540610,-10653797,30336522,-14105247,-29806336,916033,-6882542,-2986532 },
+ { -22630907,12419372,-7134229,-7473371,-16478904,16739175,285431,2763829,15736322,4143876 },
+ },
+ {
+ { 2379352,11839345,-4110402,-5988665,11274298,794957,212801,-14594663,23527084,-16458268 },
+ { 33431127,-11130478,-17838966,-15626900,8909499,8376530,-32625340,4087881,-15188911,-14416214 },
+ { 1767683,7197987,-13205226,-2022635,-13091350,448826,5799055,4357868,-4774191,-16323038 },
+ },
+},
+{
+ {
+ { 6721966,13833823,-23523388,-1551314,26354293,-11863321,23365147,-3949732,7390890,2759800 },
+ { 4409041,2052381,23373853,10530217,7676779,-12885954,21302353,-4264057,1244380,-12919645 },
+ { -4421239,7169619,4982368,-2957590,30256825,-2777540,14086413,9208236,15886429,16489664 },
+ },
+ {
+ { 1996075,10375649,14346367,13311202,-6874135,-16438411,-13693198,398369,-30606455,-712933 },
+ { -25307465,9795880,-2777414,14878809,-33531835,14780363,13348553,12076947,-30836462,5113182 },
+ { -17770784,11797796,31950843,13929123,-25888302,12288344,-30341101,-7336386,13847711,5387222 },
+ },
+ {
+ { -18582163,-3416217,17824843,-2340966,22744343,-10442611,8763061,3617786,-19600662,10370991 },
+ { 20246567,-14369378,22358229,-543712,18507283,-10413996,14554437,-8746092,32232924,16763880 },
+ { 9648505,10094563,26416693,14745928,-30374318,-6472621,11094161,15689506,3140038,-16510092 },
+ },
+ {
+ { -16160072,5472695,31895588,4744994,8823515,10365685,-27224800,9448613,-28774454,366295 },
+ { 19153450,11523972,-11096490,-6503142,-24647631,5420647,28344573,8041113,719605,11671788 },
+ { 8678025,2694440,-6808014,2517372,4964326,11152271,-15432916,-15266516,27000813,-10195553 },
+ },
+ {
+ { -15157904,7134312,8639287,-2814877,-7235688,10421742,564065,5336097,6750977,-14521026 },
+ { 11836410,-3979488,26297894,16080799,23455045,15735944,1695823,-8819122,8169720,16220347 },
+ { -18115838,8653647,17578566,-6092619,-8025777,-16012763,-11144307,-2627664,-5990708,-14166033 },
+ },
+ {
+ { -23308498,-10968312,15213228,-10081214,-30853605,-11050004,27884329,2847284,2655861,1738395 },
+ { -27537433,-14253021,-25336301,-8002780,-9370762,8129821,21651608,-3239336,-19087449,-11005278 },
+ { 1533110,3437855,23735889,459276,29970501,11335377,26030092,5821408,10478196,8544890 },
+ },
+ {
+ { 32173121,-16129311,24896207,3921497,22579056,-3410854,19270449,12217473,17789017,-3395995 },
+ { -30552961,-2228401,-15578829,-10147201,13243889,517024,15479401,-3853233,30460520,1052596 },
+ { -11614875,13323618,32618793,8175907,-15230173,12596687,27491595,-4612359,3179268,-9478891 },
+ },
+ {
+ { 31947069,-14366651,-4640583,-15339921,-15125977,-6039709,-14756777,-16411740,19072640,-9511060 },
+ { 11685058,11822410,3158003,-13952594,33402194,-4165066,5977896,-5215017,473099,5040608 },
+ { -20290863,8198642,-27410132,11602123,1290375,-2799760,28326862,1721092,-19558642,-3131606 },
+ },
+},
+{
+ {
+ { 7881532,10687937,7578723,7738378,-18951012,-2553952,21820786,8076149,-27868496,11538389 },
+ { -19935666,3899861,18283497,-6801568,-15728660,-11249211,8754525,7446702,-5676054,5797016 },
+ { -11295600,-3793569,-15782110,-7964573,12708869,-8456199,2014099,-9050574,-2369172,-5877341 },
+ },
+ {
+ { -22472376,-11568741,-27682020,1146375,18956691,16640559,1192730,-3714199,15123619,10811505 },
+ { 14352098,-3419715,-18942044,10822655,32750596,4699007,-70363,15776356,-28886779,-11974553 },
+ { -28241164,-8072475,-4978962,-5315317,29416931,1847569,-20654173,-16484855,4714547,-9600655 },
+ },
+ {
+ { 15200332,8368572,19679101,15970074,-31872674,1959451,24611599,-4543832,-11745876,12340220 },
+ { 12876937,-10480056,33134381,6590940,-6307776,14872440,9613953,8241152,15370987,9608631 },
+ { -4143277,-12014408,8446281,-391603,4407738,13629032,-7724868,15866074,-28210621,-8814099 },
+ },
+ {
+ { 26660628,-15677655,8393734,358047,-7401291,992988,-23904233,858697,20571223,8420556 },
+ { 14620715,13067227,-15447274,8264467,14106269,15080814,33531827,12516406,-21574435,-12476749 },
+ { 236881,10476226,57258,-14677024,6472998,2466984,17258519,7256740,8791136,15069930 },
+ },
+ {
+ { 1276410,-9371918,22949635,-16322807,-23493039,-5702186,14711875,4874229,-30663140,-2331391 },
+ { 5855666,4990204,-13711848,7294284,-7804282,1924647,-1423175,-7912378,-33069337,9234253 },
+ { 20590503,-9018988,31529744,-7352666,-2706834,10650548,31559055,-11609587,18979186,13396066 },
+ },
+ {
+ { 24474287,4968103,22267082,4407354,24063882,-8325180,-18816887,13594782,33514650,7021958 },
+ { -11566906,-6565505,-21365085,15928892,-26158305,4315421,-25948728,-3916677,-21480480,12868082 },
+ { -28635013,13504661,19988037,-2132761,21078225,6443208,-21446107,2244500,-12455797,-8089383 },
+ },
+ {
+ { -30595528,13793479,-5852820,319136,-25723172,-6263899,33086546,8957937,-15233648,5540521 },
+ { -11630176,-11503902,-8119500,-7643073,2620056,1022908,-23710744,-1568984,-16128528,-14962807 },
+ { 23152971,775386,27395463,14006635,-9701118,4649512,1689819,892185,-11513277,-15205948 },
+ },
+ {
+ { 9770129,9586738,26496094,4324120,1556511,-3550024,27453819,4763127,-19179614,5867134 },
+ { -32765025,1927590,31726409,-4753295,23962434,-16019500,27846559,5931263,-29749703,-16108455 },
+ { 27461885,-2977536,22380810,1815854,-23033753,-3031938,7283490,-15148073,-19526700,7734629 },
+ },
+},
+{
+ {
+ { -8010264,-9590817,-11120403,6196038,29344158,-13430885,7585295,-3176626,18549497,15302069 },
+ { -32658337,-6171222,-7672793,-11051681,6258878,13504381,10458790,-6418461,-8872242,8424746 },
+ { 24687205,8613276,-30667046,-3233545,1863892,-1830544,19206234,7134917,-11284482,-828919 },
+ },
+ {
+ { 11334899,-9218022,8025293,12707519,17523892,-10476071,10243738,-14685461,-5066034,16498837 },
+ { 8911542,6887158,-9584260,-6958590,11145641,-9543680,17303925,-14124238,6536641,10543906 },
+ { -28946384,15479763,-17466835,568876,-1497683,11223454,-2669190,-16625574,-27235709,8876771 },
+ },
+ {
+ { -25742899,-12566864,-15649966,-846607,-33026686,-796288,-33481822,15824474,-604426,-9039817 },
+ { 10330056,70051,7957388,-9002667,9764902,15609756,27698697,-4890037,1657394,3084098 },
+ { 10477963,-7470260,12119566,-13250805,29016247,-5365589,31280319,14396151,-30233575,15272409 },
+ },
+ {
+ { -12288309,3169463,28813183,16658753,25116432,-5630466,-25173957,-12636138,-25014757,1950504 },
+ { -26180358,9489187,11053416,-14746161,-31053720,5825630,-8384306,-8767532,15341279,8373727 },
+ { 28685821,7759505,-14378516,-12002860,-31971820,4079242,298136,-10232602,-2878207,15190420 },
+ },
+ {
+ { -32932876,13806336,-14337485,-15794431,-24004620,10940928,8669718,2742393,-26033313,-6875003 },
+ { -1580388,-11729417,-25979658,-11445023,-17411874,-10912854,9291594,-16247779,-12154742,6048605 },
+ { -30305315,14843444,1539301,11864366,20201677,1900163,13934231,5128323,11213262,9168384 },
+ },
+ {
+ { -26280513,11007847,19408960,-940758,-18592965,-4328580,-5088060,-11105150,20470157,-16398701 },
+ { -23136053,9282192,14855179,-15390078,-7362815,-14408560,-22783952,14461608,14042978,5230683 },
+ { 29969567,-2741594,-16711867,-8552442,9175486,-2468974,21556951,3506042,-5933891,-12449708 },
+ },
+ {
+ { -3144746,8744661,19704003,4581278,-20430686,6830683,-21284170,8971513,-28539189,15326563 },
+ { -19464629,10110288,-17262528,-3503892,-23500387,1355669,-15523050,15300988,-20514118,9168260 },
+ { -5353335,4488613,-23803248,16314347,7780487,-15638939,-28948358,9601605,33087103,-9011387 },
+ },
+ {
+ { -19443170,-15512900,-20797467,-12445323,-29824447,10229461,-27444329,-15000531,-5996870,15664672 },
+ { 23294591,-16632613,-22650781,-8470978,27844204,11461195,13099750,-2460356,18151676,13417686 },
+ { -24722913,-4176517,-31150679,5988919,-26858785,6685065,1661597,-12551441,15271676,-15452665 },
+ },
+},
+{
+ {
+ { 11433042,-13228665,8239631,-5279517,-1985436,-725718,-18698764,2167544,-6921301,-13440182 },
+ { -31436171,15575146,30436815,12192228,-22463353,9395379,-9917708,-8638997,12215110,12028277 },
+ { 14098400,6555944,23007258,5757252,-15427832,-12950502,30123440,4617780,-16900089,-655628 },
+ },
+ {
+ { -4026201,-15240835,11893168,13718664,-14809462,1847385,-15819999,10154009,23973261,-12684474 },
+ { -26531820,-3695990,-1908898,2534301,-31870557,-16550355,18341390,-11419951,32013174,-10103539 },
+ { -25479301,10876443,-11771086,-14625140,-12369567,1838104,21911214,6354752,4425632,-837822 },
+ },
+ {
+ { -10433389,-14612966,22229858,-3091047,-13191166,776729,-17415375,-12020462,4725005,14044970 },
+ { 19268650,-7304421,1555349,8692754,-21474059,-9910664,6347390,-1411784,-19522291,-16109756 },
+ { -24864089,12986008,-10898878,-5558584,-11312371,-148526,19541418,8180106,9282262,10282508 },
+ },
+ {
+ { -26205082,4428547,-8661196,-13194263,4098402,-14165257,15522535,8372215,5542595,-10702683 },
+ { -10562541,14895633,26814552,-16673850,-17480754,-2489360,-2781891,6993761,-18093885,10114655 },
+ { -20107055,-929418,31422704,10427861,-7110749,6150669,-29091755,-11529146,25953725,-106158 },
+ },
+ {
+ { -4234397,-8039292,-9119125,3046000,2101609,-12607294,19390020,6094296,-3315279,12831125 },
+ { -15998678,7578152,5310217,14408357,-33548620,-224739,31575954,6326196,7381791,-2421839 },
+ { -20902779,3296811,24736065,-16328389,18374254,7318640,6295303,8082724,-15362489,12339664 },
+ },
+ {
+ { 27724736,2291157,6088201,-14184798,1792727,5857634,13848414,15768922,25091167,14856294 },
+ { -18866652,8331043,24373479,8541013,-701998,-9269457,12927300,-12695493,-22182473,-9012899 },
+ { -11423429,-5421590,11632845,3405020,30536730,-11674039,-27260765,13866390,30146206,9142070 },
+ },
+ {
+ { 3924129,-15307516,-13817122,-10054960,12291820,-668366,-27702774,9326384,-8237858,4171294 },
+ { -15921940,16037937,6713787,16606682,-21612135,2790944,26396185,3731949,345228,-5462949 },
+ { -21327538,13448259,25284571,1143661,20614966,-8849387,2031539,-12391231,-16253183,-13582083 },
+ },
+ {
+ { 31016211,-16722429,26371392,-14451233,-5027349,14854137,17477601,3842657,28012650,-16405420 },
+ { -5075835,9368966,-8562079,-4600902,-15249953,6970560,-9189873,16292057,-8867157,3507940 },
+ { 29439664,3537914,23333589,6997794,-17555561,-11018068,-15209202,-15051267,-9164929,6580396 },
+ },
+},
+{
+ {
+ { -12185861,-7679788,16438269,10826160,-8696817,-6235611,17860444,-9273846,-2095802,9304567 },
+ { 20714564,-4336911,29088195,7406487,11426967,-5095705,14792667,-14608617,5289421,-477127 },
+ { -16665533,-10650790,-6160345,-13305760,9192020,-1802462,17271490,12349094,26939669,-3752294 },
+ },
+ {
+ { -12889898,9373458,31595848,16374215,21471720,13221525,-27283495,-12348559,-3698806,117887 },
+ { 22263325,-6560050,3984570,-11174646,-15114008,-566785,28311253,5358056,-23319780,541964 },
+ { 16259219,3261970,2309254,-15534474,-16885711,-4581916,24134070,-16705829,-13337066,-13552195 },
+ },
+ {
+ { 9378160,-13140186,-22845982,-12745264,28198281,-7244098,-2399684,-717351,690426,14876244 },
+ { 24977353,-314384,-8223969,-13465086,28432343,-1176353,-13068804,-12297348,-22380984,6618999 },
+ { -1538174,11685646,12944378,13682314,-24389511,-14413193,8044829,-13817328,32239829,-5652762 },
+ },
+ {
+ { -18603066,4762990,-926250,8885304,-28412480,-3187315,9781647,-10350059,32779359,5095274 },
+ { -33008130,-5214506,-32264887,-3685216,9460461,-9327423,-24601656,14506724,21639561,-2630236 },
+ { -16400943,-13112215,25239338,15531969,3987758,-4499318,-1289502,-6863535,17874574,558605 },
+ },
+ {
+ { -13600129,10240081,9171883,16131053,-20869254,9599700,33499487,5080151,2085892,5119761 },
+ { -22205145,-2519528,-16381601,414691,-25019550,2170430,30634760,-8363614,-31999993,-5759884 },
+ { -6845704,15791202,8550074,-1312654,29928809,-12092256,27534430,-7192145,-22351378,12961482 },
+ },
+ {
+ { -24492060,-9570771,10368194,11582341,-23397293,-2245287,16533930,8206996,-30194652,-5159638 },
+ { -11121496,-3382234,2307366,6362031,-135455,8868177,-16835630,7031275,7589640,8945490 },
+ { -32152748,8917967,6661220,-11677616,-1192060,-15793393,7251489,-11182180,24099109,-14456170 },
+ },
+ {
+ { 5019558,-7907470,4244127,-14714356,-26933272,6453165,-19118182,-13289025,-6231896,-10280736 },
+ { 10853594,10721687,26480089,5861829,-22995819,1972175,-1866647,-10557898,-3363451,-6441124 },
+ { -17002408,5906790,221599,-6563147,7828208,-13248918,24362661,-2008168,-13866408,7421392 },
+ },
+ {
+ { 8139927,-6546497,32257646,-5890546,30375719,1886181,-21175108,15441252,28826358,-4123029 },
+ { 6267086,9695052,7709135,-16603597,-32869068,-1886135,14795160,-7840124,13746021,-1742048 },
+ { 28584902,7787108,-6732942,-15050729,22846041,-7571236,-3181936,-363524,4771362,-8419958 },
+ },
+},
+{
+ {
+ { 24949256,6376279,-27466481,-8174608,-18646154,-9930606,33543569,-12141695,3569627,11342593 },
+ { 26514989,4740088,27912651,3697550,19331575,-11472339,6809886,4608608,7325975,-14801071 },
+ { -11618399,-14554430,-24321212,7655128,-1369274,5214312,-27400540,10258390,-17646694,-8186692 },
+ },
+ {
+ { 11431204,15823007,26570245,14329124,18029990,4796082,-31446179,15580664,9280358,-3973687 },
+ { -160783,-10326257,-22855316,-4304997,-20861367,-13621002,-32810901,-11181622,-15545091,4387441 },
+ { -20799378,12194512,3937617,-5805892,-27154820,9340370,-24513992,8548137,20617071,-7482001 },
+ },
+ {
+ { -938825,-3930586,-8714311,16124718,24603125,-6225393,-13775352,-11875822,24345683,10325460 },
+ { -19855277,-1568885,-22202708,8714034,14007766,6928528,16318175,-1010689,4766743,3552007 },
+ { -21751364,-16730916,1351763,-803421,-4009670,3950935,3217514,14481909,10988822,-3994762 },
+ },
+ {
+ { 15564307,-14311570,3101243,5684148,30446780,-8051356,12677127,-6505343,-8295852,13296005 },
+ { -9442290,6624296,-30298964,-11913677,-4670981,-2057379,31521204,9614054,-30000824,12074674 },
+ { 4771191,-135239,14290749,-13089852,27992298,14998318,-1413936,-1556716,29832613,-16391035 },
+ },
+ {
+ { 7064884,-7541174,-19161962,-5067537,-18891269,-2912736,25825242,5293297,-27122660,13101590 },
+ { -2298563,2439670,-7466610,1719965,-27267541,-16328445,32512469,-5317593,-30356070,-4190957 },
+ { -30006540,10162316,-33180176,3981723,-16482138,-13070044,14413974,9515896,19568978,9628812 },
+ },
+ {
+ { 33053803,199357,15894591,1583059,27380243,-4580435,-17838894,-6106839,-6291786,3437740 },
+ { -18978877,3884493,19469877,12726490,15913552,13614290,-22961733,70104,7463304,4176122 },
+ { -27124001,10659917,11482427,-16070381,12771467,-6635117,-32719404,-5322751,24216882,5944158 },
+ },
+ {
+ { 8894125,7450974,-2664149,-9765752,-28080517,-12389115,19345746,14680796,11632993,5847885 },
+ { 26942781,-2315317,9129564,-4906607,26024105,11769399,-11518837,6367194,-9727230,4782140 },
+ { 19916461,-4828410,-22910704,-11414391,25606324,-5972441,33253853,8220911,6358847,-1873857 },
+ },
+ {
+ { 801428,-2081702,16569428,11065167,29875704,96627,7908388,-4480480,-13538503,1387155 },
+ { 19646058,5720633,-11416706,12814209,11607948,12749789,14147075,15156355,-21866831,11835260 },
+ { 19299512,1155910,28703737,14890794,2925026,7269399,26121523,15467869,-26560550,5052483 },
+ },
+},
+{
+ {
+ { -3017432,10058206,1980837,3964243,22160966,12322533,-6431123,-12618185,12228557,-7003677 },
+ { 32944382,14922211,-22844894,5188528,21913450,-8719943,4001465,13238564,-6114803,8653815 },
+ { 22865569,-4652735,27603668,-12545395,14348958,8234005,24808405,5719875,28483275,2841751 },
+ },
+ {
+ { -16420968,-1113305,-327719,-12107856,21886282,-15552774,-1887966,-315658,19932058,-12739203 },
+ { -11656086,10087521,-8864888,-5536143,-19278573,-3055912,3999228,13239134,-4777469,-13910208 },
+ { 1382174,-11694719,17266790,9194690,-13324356,9720081,20403944,11284705,-14013818,3093230 },
+ },
+ {
+ { 16650921,-11037932,-1064178,1570629,-8329746,7352753,-302424,16271225,-24049421,-6691850 },
+ { -21911077,-5927941,-4611316,-5560156,-31744103,-10785293,24123614,15193618,-21652117,-16739389 },
+ { -9935934,-4289447,-25279823,4372842,2087473,10399484,31870908,14690798,17361620,11864968 },
+ },
+ {
+ { -11307610,6210372,13206574,5806320,-29017692,-13967200,-12331205,-7486601,-25578460,-16240689 },
+ { 14668462,-12270235,26039039,15305210,25515617,4542480,10453892,6577524,9145645,-6443880 },
+ { 5974874,3053895,-9433049,-10385191,-31865124,3225009,-7972642,3936128,-5652273,-3050304 },
+ },
+ {
+ { 30625386,-4729400,-25555961,-12792866,-20484575,7695099,17097188,-16303496,-27999779,1803632 },
+ { -3553091,9865099,-5228566,4272701,-5673832,-16689700,14911344,12196514,-21405489,7047412 },
+ { 20093277,9920966,-11138194,-5343857,13161587,12044805,-32856851,4124601,-32343828,-10257566 },
+ },
+ {
+ { -20788824,14084654,-13531713,7842147,19119038,-13822605,4752377,-8714640,-21679658,2288038 },
+ { -26819236,-3283715,29965059,3039786,-14473765,2540457,29457502,14625692,-24819617,12570232 },
+ { -1063558,-11551823,16920318,12494842,1278292,-5869109,-21159943,-3498680,-11974704,4724943 },
+ },
+ {
+ { 17960970,-11775534,-4140968,-9702530,-8876562,-1410617,-12907383,-8659932,-29576300,1903856 },
+ { 23134274,-14279132,-10681997,-1611936,20684485,15770816,-12989750,3190296,26955097,14109738 },
+ { 15308788,5320727,-30113809,-14318877,22902008,7767164,29425325,-11277562,31960942,11934971 },
+ },
+ {
+ { -27395711,8435796,4109644,12222639,-24627868,14818669,20638173,4875028,10491392,1379718 },
+ { -13159415,9197841,3875503,-8936108,-1383712,-5879801,33518459,16176658,21432314,12180697 },
+ { -11787308,11500838,13787581,-13832590,-22430679,10140205,1465425,12689540,-10301319,-13872883 },
+ },
+},
+{
+ {
+ { 5414091,-15386041,-21007664,9643570,12834970,1186149,-2622916,-1342231,26128231,6032912 },
+ { -26337395,-13766162,32496025,-13653919,17847801,-12669156,3604025,8316894,-25875034,-10437358 },
+ { 3296484,6223048,24680646,-12246460,-23052020,5903205,-8862297,-4639164,12376617,3188849 },
+ },
+ {
+ { 29190488,-14659046,27549113,-1183516,3520066,-10697301,32049515,-7309113,-16109234,-9852307 },
+ { -14744486,-9309156,735818,-598978,-20407687,-5057904,25246078,-15795669,18640741,-960977 },
+ { -6928835,-16430795,10361374,5642961,4910474,12345252,-31638386,-494430,10530747,1053335 },
+ },
+ {
+ { -29265967,-14186805,-13538216,-12117373,-19457059,-10655384,-31462369,-2948985,24018831,15026644 },
+ { -22592535,-3145277,-2289276,5953843,-13440189,9425631,25310643,13003497,-2314791,-15145616 },
+ { -27419985,-603321,-8043984,-1669117,-26092265,13987819,-27297622,187899,-23166419,-2531735 },
+ },
+ {
+ { -21744398,-13810475,1844840,5021428,-10434399,-15911473,9716667,16266922,-5070217,726099 },
+ { 29370922,-6053998,7334071,-15342259,9385287,2247707,-13661962,-4839461,30007388,-15823341 },
+ { -936379,16086691,23751945,-543318,-1167538,-5189036,9137109,730663,9835848,4555336 },
+ },
+ {
+ { -23376435,1410446,-22253753,-12899614,30867635,15826977,17693930,544696,-11985298,12422646 },
+ { 31117226,-12215734,-13502838,6561947,-9876867,-12757670,-5118685,-4096706,29120153,13924425 },
+ { -17400879,-14233209,19675799,-2734756,-11006962,-5858820,-9383939,-11317700,7240931,-237388 },
+ },
+ {
+ { -31361739,-11346780,-15007447,-5856218,-22453340,-12152771,1222336,4389483,3293637,-15551743 },
+ { -16684801,-14444245,11038544,11054958,-13801175,-3338533,-24319580,7733547,12796905,-6335822 },
+ { -8759414,-10817836,-25418864,10783769,-30615557,-9746811,-28253339,3647836,3222231,-11160462 },
+ },
+ {
+ { 18606113,1693100,-25448386,-15170272,4112353,10045021,23603893,-2048234,-7550776,2484985 },
+ { 9255317,-3131197,-12156162,-1004256,13098013,-9214866,16377220,-2102812,-19802075,-3034702 },
+ { -22729289,7496160,-5742199,11329249,19991973,-3347502,-31718148,9936966,-30097688,-10618797 },
+ },
+ {
+ { 21878590,-5001297,4338336,13643897,-3036865,13160960,19708896,5415497,-7360503,-4109293 },
+ { 27736861,10103576,12500508,8502413,-3413016,-9633558,10436918,-1550276,-23659143,-8132100 },
+ { 19492550,-12104365,-29681976,-852630,-3208171,12403437,30066266,8367329,13243957,8709688 },
+ },
+},
+{
+ {
+ { 12015105,2801261,28198131,10151021,24818120,-4743133,-11194191,-5645734,5150968,7274186 },
+ { 2831366,-12492146,1478975,6122054,23825128,-12733586,31097299,6083058,31021603,-9793610 },
+ { -2529932,-2229646,445613,10720828,-13849527,-11505937,-23507731,16354465,15067285,-14147707 },
+ },
+ {
+ { 7840942,14037873,-33364863,15934016,-728213,-3642706,21403988,1057586,-19379462,-12403220 },
+ { 915865,-16469274,15608285,-8789130,-24357026,6060030,-17371319,8410997,-7220461,16527025 },
+ { 32922597,-556987,20336074,-16184568,10903705,-5384487,16957574,52992,23834301,6588044 },
+ },
+ {
+ { 32752030,11232950,3381995,-8714866,22652988,-10744103,17159699,16689107,-20314580,-1305992 },
+ { -4689649,9166776,-25710296,-10847306,11576752,12733943,7924251,-2752281,1976123,-7249027 },
+ { 21251222,16309901,-2983015,-6783122,30810597,12967303,156041,-3371252,12331345,-8237197 },
+ },
+ {
+ { 8651614,-4477032,-16085636,-4996994,13002507,2950805,29054427,-5106970,10008136,-4667901 },
+ { 31486080,15114593,-14261250,12951354,14369431,-7387845,16347321,-13662089,8684155,-10532952 },
+ { 19443825,11385320,24468943,-9659068,-23919258,2187569,-26263207,-6086921,31316348,14219878 },
+ },
+ {
+ { -28594490,1193785,32245219,11392485,31092169,15722801,27146014,6992409,29126555,9207390 },
+ { 32382935,1110093,18477781,11028262,-27411763,-7548111,-4980517,10843782,-7957600,-14435730 },
+ { 2814918,7836403,27519878,-7868156,-20894015,-11553689,-21494559,8550130,28346258,1994730 },
+ },
+ {
+ { -19578299,8085545,-14000519,-3948622,2785838,-16231307,-19516951,7174894,22628102,8115180 },
+ { -30405132,955511,-11133838,-15078069,-32447087,-13278079,-25651578,3317160,-9943017,930272 },
+ { -15303681,-6833769,28856490,1357446,23421993,1057177,24091212,-1388970,-22765376,-10650715 },
+ },
+ {
+ { -22751231,-5303997,-12907607,-12768866,-15811511,-7797053,-14839018,-16554220,-1867018,8398970 },
+ { -31969310,2106403,-4736360,1362501,12813763,16200670,22981545,-6291273,18009408,-15772772 },
+ { -17220923,-9545221,-27784654,14166835,29815394,7444469,29551787,-3727419,19288549,1325865 },
+ },
+ {
+ { 15100157,-15835752,-23923978,-1005098,-26450192,15509408,12376730,-3479146,33166107,-8042750 },
+ { 20909231,13023121,-9209752,16251778,-5778415,-8094914,12412151,10018715,2213263,-13878373 },
+ { 32529814,-11074689,30361439,-16689753,-9135940,1513226,22922121,6382134,-5766928,8371348 },
+ },
+},
+{
+ {
+ { 9923462,11271500,12616794,3544722,-29998368,-1721626,12891687,-8193132,-26442943,10486144 },
+ { -22597207,-7012665,8587003,-8257861,4084309,-12970062,361726,2610596,-23921530,-11455195 },
+ { 5408411,-1136691,-4969122,10561668,24145918,14240566,31319731,-4235541,19985175,-3436086 },
+ },
+ {
+ { -13994457,16616821,14549246,3341099,32155958,13648976,-17577068,8849297,65030,8370684 },
+ { -8320926,-12049626,31204563,5839400,-20627288,-1057277,-19442942,6922164,12743482,-9800518 },
+ { -2361371,12678785,28815050,4759974,-23893047,4884717,23783145,11038569,18800704,255233 },
+ },
+ {
+ { -5269658,-1773886,13957886,7990715,23132995,728773,13393847,9066957,19258688,-14753793 },
+ { -2936654,-10827535,-10432089,14516793,-3640786,4372541,-31934921,2209390,-1524053,2055794 },
+ { 580882,16705327,5468415,-2683018,-30926419,-14696000,-7203346,-8994389,-30021019,7394435 },
+ },
+ {
+ { 23838809,1822728,-15738443,15242727,8318092,-3733104,-21672180,-3492205,-4821741,14799921 },
+ { 13345610,9759151,3371034,-16137791,16353039,8577942,31129804,13496856,-9056018,7402518 },
+ { 2286874,-4435931,-20042458,-2008336,-13696227,5038122,11006906,-15760352,8205061,1607563 },
+ },
+ {
+ { 14414086,-8002132,3331830,-3208217,22249151,-5594188,18364661,-2906958,30019587,-9029278 },
+ { -27688051,1585953,-10775053,931069,-29120221,-11002319,-14410829,12029093,9944378,8024 },
+ { 4368715,-3709630,29874200,-15022983,-20230386,-11410704,-16114594,-999085,-8142388,5640030 },
+ },
+ {
+ { 10299610,13746483,11661824,16234854,7630238,5998374,9809887,-16694564,15219798,-14327783 },
+ { 27425505,-5719081,3055006,10660664,23458024,595578,-15398605,-1173195,-18342183,9742717 },
+ { 6744077,2427284,26042789,2720740,-847906,1118974,32324614,7406442,12420155,1994844 },
+ },
+ {
+ { 14012521,-5024720,-18384453,-9578469,-26485342,-3936439,-13033478,-10909803,24319929,-6446333 },
+ { 16412690,-4507367,10772641,15929391,-17068788,-4658621,10555945,-10484049,-30102368,-4739048 },
+ { 22397382,-7767684,-9293161,-12792868,17166287,-9755136,-27333065,6199366,21880021,-12250760 },
+ },
+ {
+ { -4283307,5368523,-31117018,8163389,-30323063,3209128,16557151,8890729,8840445,4957760 },
+ { -15447727,709327,-6919446,-10870178,-29777922,6522332,-21720181,12130072,-14796503,5005757 },
+ { -2114751,-14308128,23019042,15765735,-25269683,6002752,10183197,-13239326,-16395286,-2176112 },
+ },
+},
+{
+ {
+ { -19025756,1632005,13466291,-7995100,-23640451,16573537,-32013908,-3057104,22208662,2000468 },
+ { 3065073,-1412761,-25598674,-361432,-17683065,-5703415,-8164212,11248527,-3691214,-7414184 },
+ { 10379208,-6045554,8877319,1473647,-29291284,-12507580,16690915,2553332,-3132688,16400289 },
+ },
+ {
+ { 15716668,1254266,-18472690,7446274,-8448918,6344164,-22097271,-7285580,26894937,9132066 },
+ { 24158887,12938817,11085297,-8177598,-28063478,-4457083,-30576463,64452,-6817084,-2692882 },
+ { 13488534,7794716,22236231,5989356,25426474,-12578208,2350710,-3418511,-4688006,2364226 },
+ },
+ {
+ { 16335052,9132434,25640582,6678888,1725628,8517937,-11807024,-11697457,15445875,-7798101 },
+ { 29004207,-7867081,28661402,-640412,-12794003,-7943086,31863255,-4135540,-278050,-15759279 },
+ { -6122061,-14866665,-28614905,14569919,-10857999,-3591829,10343412,-6976290,-29828287,-10815811 },
+ },
+ {
+ { 27081650,3463984,14099042,-4517604,1616303,-6205604,29542636,15372179,17293797,960709 },
+ { 20263915,11434237,-5765435,11236810,13505955,-10857102,-16111345,6493122,-19384511,7639714 },
+ { -2830798,-14839232,25403038,-8215196,-8317012,-16173699,18006287,-16043750,29994677,-15808121 },
+ },
+ {
+ { 9769828,5202651,-24157398,-13631392,-28051003,-11561624,-24613141,-13860782,-31184575,709464 },
+ { 12286395,13076066,-21775189,-1176622,-25003198,4057652,-32018128,-8890874,16102007,13205847 },
+ { 13733362,5599946,10557076,3195751,-5557991,8536970,-25540170,8525972,10151379,10394400 },
+ },
+ {
+ { 4024660,-16137551,22436262,12276534,-9099015,-2686099,19698229,11743039,-33302334,8934414 },
+ { -15879800,-4525240,-8580747,-2934061,14634845,-698278,-9449077,3137094,-11536886,11721158 },
+ { 17555939,-5013938,8268606,2331751,-22738815,9761013,9319229,8835153,-9205489,-1280045 },
+ },
+ {
+ { -461409,-7830014,20614118,16688288,-7514766,-4807119,22300304,505429,6108462,-6183415 },
+ { -5070281,12367917,-30663534,3234473,32617080,-8422642,29880583,-13483331,-26898490,-7867459 },
+ { -31975283,5726539,26934134,10237677,-3173717,-605053,24199304,3795095,7592688,-14992079 },
+ },
+ {
+ { 21594432,-14964228,17466408,-4077222,32537084,2739898,6407723,12018833,-28256052,4298412 },
+ { -20650503,-11961496,-27236275,570498,3767144,-1717540,13891942,-1569194,13717174,10805743 },
+ { -14676630,-15644296,15287174,11927123,24177847,-8175568,-796431,14860609,-26938930,-5863836 },
+ },
+},
+{
+ {
+ { 12962541,5311799,-10060768,11658280,18855286,-7954201,13286263,-12808704,-4381056,9882022 },
+ { 18512079,11319350,-20123124,15090309,18818594,5271736,-22727904,3666879,-23967430,-3299429 },
+ { -6789020,-3146043,16192429,13241070,15898607,-14206114,-10084880,-6661110,-2403099,5276065 },
+ },
+ {
+ { 30169808,-5317648,26306206,-11750859,27814964,7069267,7152851,3684982,1449224,13082861 },
+ { 10342826,3098505,2119311,193222,25702612,12233820,23697382,15056736,-21016438,-8202000 },
+ { -33150110,3261608,22745853,7948688,19370557,-15177665,-26171976,6482814,-10300080,-11060101 },
+ },
+ {
+ { 32869458,-5408545,25609743,15678670,-10687769,-15471071,26112421,2521008,-22664288,6904815 },
+ { 29506923,4457497,3377935,-9796444,-30510046,12935080,1561737,3841096,-29003639,-6657642 },
+ { 10340844,-6630377,-18656632,-2278430,12621151,-13339055,30878497,-11824370,-25584551,5181966 },
+ },
+ {
+ { 25940115,-12658025,17324188,-10307374,-8671468,15029094,24396252,-16450922,-2322852,-12388574 },
+ { -21765684,9916823,-1300409,4079498,-1028346,11909559,1782390,12641087,20603771,-6561742 },
+ { -18882287,-11673380,24849422,11501709,13161720,-4768874,1925523,11914390,4662781,7820689 },
+ },
+ {
+ { 12241050,-425982,8132691,9393934,32846760,-1599620,29749456,12172924,16136752,15264020 },
+ { -10349955,-14680563,-8211979,2330220,-17662549,-14545780,10658213,6671822,19012087,3772772 },
+ { 3753511,-3421066,10617074,2028709,14841030,-6721664,28718732,-15762884,20527771,12988982 },
+ },
+ {
+ { -14822485,-5797269,-3707987,12689773,-898983,-10914866,-24183046,-10564943,3299665,-12424953 },
+ { -16777703,-15253301,-9642417,4978983,3308785,8755439,6943197,6461331,-25583147,8991218 },
+ { -17226263,1816362,-1673288,-6086439,31783888,-8175991,-32948145,7417950,-30242287,1507265 },
+ },
+ {
+ { 29692663,6829891,-10498800,4334896,20945975,-11906496,-28887608,8209391,14606362,-10647073 },
+ { -3481570,8707081,32188102,5672294,22096700,1711240,-33020695,9761487,4170404,-2085325 },
+ { -11587470,14855945,-4127778,-1531857,-26649089,15084046,22186522,16002000,-14276837,-8400798 },
+ },
+ {
+ { -4811456,13761029,-31703877,-2483919,-3312471,7869047,-7113572,-9620092,13240845,10965870 },
+ { -7742563,-8256762,-14768334,-13656260,-23232383,12387166,4498947,14147411,29514390,4302863 },
+ { -13413405,-12407859,20757302,-13801832,14785143,8976368,-5061276,-2144373,17846988,-13971927 },
+ },
+},
+{
+ {
+ { -2244452,-754728,-4597030,-1066309,-6247172,1455299,-21647728,-9214789,-5222701,12650267 },
+ { -9906797,-16070310,21134160,12198166,-27064575,708126,387813,13770293,-19134326,10958663 },
+ { 22470984,12369526,23446014,-5441109,-21520802,-9698723,-11772496,-11574455,-25083830,4271862 },
+ },
+ {
+ { -25169565,-10053642,-19909332,15361595,-5984358,2159192,75375,-4278529,-32526221,8469673 },
+ { 15854970,4148314,-8893890,7259002,11666551,13824734,-30531198,2697372,24154791,-9460943 },
+ { 15446137,-15806644,29759747,14019369,30811221,-9610191,-31582008,12840104,24913809,9815020 },
+ },
+ {
+ { -4709286,-5614269,-31841498,-12288893,-14443537,10799414,-9103676,13438769,18735128,9466238 },
+ { 11933045,9281483,5081055,-5183824,-2628162,-4905629,-7727821,-10896103,-22728655,16199064 },
+ { 14576810,379472,-26786533,-8317236,-29426508,-10812974,-102766,1876699,30801119,2164795 },
+ },
+ {
+ { 15995086,3199873,13672555,13712240,-19378835,-4647646,-13081610,-15496269,-13492807,1268052 },
+ { -10290614,-3659039,-3286592,10948818,23037027,3794475,-3470338,-12600221,-17055369,3565904 },
+ { 29210088,-9419337,-5919792,-4952785,10834811,-13327726,-16512102,-10820713,-27162222,-14030531 },
+ },
+ {
+ { -13161890,15508588,16663704,-8156150,-28349942,9019123,-29183421,-3769423,2244111,-14001979 },
+ { -5152875,-3800936,-9306475,-6071583,16243069,14684434,-25673088,-16180800,13491506,4641841 },
+ { 10813417,643330,-19188515,-728916,30292062,-16600078,27548447,-7721242,14476989,-12767431 },
+ },
+ {
+ { 10292079,9984945,6481436,8279905,-7251514,7032743,27282937,-1644259,-27912810,12651324 },
+ { -31185513,-813383,22271204,11835308,10201545,15351028,17099662,3988035,21721536,-3148940 },
+ { 10202177,-6545839,-31373232,-9574638,-32150642,-8119683,-12906320,3852694,13216206,14842320 },
+ },
+ {
+ { -15815640,-10601066,-6538952,-7258995,-6984659,-6581778,-31500847,13765824,-27434397,9900184 },
+ { 14465505,-13833331,-32133984,-14738873,-27443187,12990492,33046193,15796406,-7051866,-8040114 },
+ { 30924417,-8279620,6359016,-12816335,16508377,9071735,-25488601,15413635,9524356,-7018878 },
+ },
+ {
+ { 12274201,-13175547,32627641,-1785326,6736625,13267305,5237659,-5109483,15663516,4035784 },
+ { -2951309,8903985,17349946,601635,-16432815,-4612556,-13732739,-15889334,-22258478,4659091 },
+ { -16916263,-4952973,-30393711,-15158821,20774812,15897498,5736189,15026997,-2178256,-13455585 },
+ },
+},
+{
+ {
+ { -8858980,-2219056,28571666,-10155518,-474467,-10105698,-3801496,278095,23440562,-290208 },
+ { 10226241,-5928702,15139956,120818,-14867693,5218603,32937275,11551483,-16571960,-7442864 },
+ { 17932739,-12437276,-24039557,10749060,11316803,7535897,22503767,5561594,-3646624,3898661 },
+ },
+ {
+ { 7749907,-969567,-16339731,-16464,-25018111,15122143,-1573531,7152530,21831162,1245233 },
+ { 26958459,-14658026,4314586,8346991,-5677764,11960072,-32589295,-620035,-30402091,-16716212 },
+ { -12165896,9166947,33491384,13673479,29787085,13096535,6280834,14587357,-22338025,13987525 },
+ },
+ {
+ { -24349909,7778775,21116000,15572597,-4833266,-5357778,-4300898,-5124639,-7469781,-2858068 },
+ { 9681908,-6737123,-31951644,13591838,-6883821,386950,31622781,6439245,-14581012,4091397 },
+ { -8426427,1470727,-28109679,-1596990,3978627,-5123623,-19622683,12092163,29077877,-14741988 },
+ },
+ {
+ { 5269168,-6859726,-13230211,-8020715,25932563,1763552,-5606110,-5505881,-20017847,2357889 },
+ { 32264008,-15407652,-5387735,-1160093,-2091322,-3946900,23104804,-12869908,5727338,189038 },
+ { 14609123,-8954470,-6000566,-16622781,-14577387,-7743898,-26745169,10942115,-25888931,-14884697 },
+ },
+ {
+ { 20513500,5557931,-15604613,7829531,26413943,-2019404,-21378968,7471781,13913677,-5137875 },
+ { -25574376,11967826,29233242,12948236,-6754465,4713227,-8940970,14059180,12878652,8511905 },
+ { -25656801,3393631,-2955415,-7075526,-2250709,9366908,-30223418,6812974,5568676,-3127656 },
+ },
+ {
+ { 11630004,12144454,2116339,13606037,27378885,15676917,-17408753,-13504373,-14395196,8070818 },
+ { 27117696,-10007378,-31282771,-5570088,1127282,12772488,-29845906,10483306,-11552749,-1028714 },
+ { 10637467,-5688064,5674781,1072708,-26343588,-6982302,-1683975,9177853,-27493162,15431203 },
+ },
+ {
+ { 20525145,10892566,-12742472,12779443,-29493034,16150075,-28240519,14943142,-15056790,-7935931 },
+ { -30024462,5626926,-551567,-9981087,753598,11981191,25244767,-3239766,-3356550,9594024 },
+ { -23752644,2636870,-5163910,-10103818,585134,7877383,11345683,-6492290,13352335,-10977084 },
+ },
+ {
+ { -1931799,-5407458,3304649,-12884869,17015806,-4877091,-29783850,-7752482,-13215537,-319204 },
+ { 20239939,6607058,6203985,3483793,-18386976,-779229,-20723742,15077870,-22750759,14523817 },
+ { 27406042,-6041657,27423596,-4497394,4996214,10002360,-28842031,-4545494,-30172742,-4805667 },
+ },
+},
+{
+ {
+ { 11374242,12660715,17861383,-12540833,10935568,1099227,-13886076,-9091740,-27727044,11358504 },
+ { -12730809,10311867,1510375,10778093,-2119455,-9145702,32676003,11149336,-26123651,4985768 },
+ { -19096303,341147,-6197485,-239033,15756973,-8796662,-983043,13794114,-19414307,-15621255 },
+ },
+ {
+ { 6490081,11940286,25495923,-7726360,8668373,-8751316,3367603,6970005,-1691065,-9004790 },
+ { 1656497,13457317,15370807,6364910,13605745,8362338,-19174622,-5475723,-16796596,-5031438 },
+ { -22273315,-13524424,-64685,-4334223,-18605636,-10921968,-20571065,-7007978,-99853,-10237333 },
+ },
+ {
+ { 17747465,10039260,19368299,-4050591,-20630635,-16041286,31992683,-15857976,-29260363,-5511971 },
+ { 31932027,-4986141,-19612382,16366580,22023614,88450,11371999,-3744247,4882242,-10626905 },
+ { 29796507,37186,19818052,10115756,-11829032,3352736,18551198,3272828,-5190932,-4162409 },
+ },
+ {
+ { 12501286,4044383,-8612957,-13392385,-32430052,5136599,-19230378,-3529697,330070,-3659409 },
+ { 6384877,2899513,17807477,7663917,-2358888,12363165,25366522,-8573892,-271295,12071499 },
+ { -8365515,-4042521,25133448,-4517355,-6211027,2265927,-32769618,1936675,-5159697,3829363 },
+ },
+ {
+ { 28425966,-5835433,-577090,-4697198,-14217555,6870930,7921550,-6567787,26333140,14267664 },
+ { -11067219,11871231,27385719,-10559544,-4585914,-11189312,10004786,-8709488,-21761224,8930324 },
+ { -21197785,-16396035,25654216,-1725397,12282012,11008919,1541940,4757911,-26491501,-16408940 },
+ },
+ {
+ { 13537262,-7759490,-20604840,10961927,-5922820,-13218065,-13156584,6217254,-15943699,13814990 },
+ { -17422573,15157790,18705543,29619,24409717,-260476,27361681,9257833,-1956526,-1776914 },
+ { -25045300,-10191966,15366585,15166509,-13105086,8423556,-29171540,12361135,-18685978,4578290 },
+ },
+ {
+ { 24579768,3711570,1342322,-11180126,-27005135,14124956,-22544529,14074919,21964432,8235257 },
+ { -6528613,-2411497,9442966,-5925588,12025640,-1487420,-2981514,-1669206,13006806,2355433 },
+ { -16304899,-13605259,-6632427,-5142349,16974359,-10911083,27202044,1719366,1141648,-12796236 },
+ },
+ {
+ { -12863944,-13219986,-8318266,-11018091,-6810145,-4843894,13475066,-3133972,32674895,13715045 },
+ { 11423335,-5468059,32344216,8962751,24989809,9241752,-13265253,16086212,-28740881,-15642093 },
+ { -1409668,12530728,-6368726,10847387,19531186,-14132160,-11709148,7791794,-27245943,4383347 },
+ },
+},
+{
+ {
+ { -28970898,5271447,-1266009,-9736989,-12455236,16732599,-4862407,-4906449,27193557,6245191 },
+ { -15193956,5362278,-1783893,2695834,4960227,12840725,23061898,3260492,22510453,8577507 },
+ { -12632451,11257346,-32692994,13548177,-721004,10879011,31168030,13952092,-29571492,-3635906 },
+ },
+ {
+ { 3877321,-9572739,32416692,5405324,-11004407,-13656635,3759769,11935320,5611860,8164018 },
+ { -16275802,14667797,15906460,12155291,-22111149,-9039718,32003002,-8832289,5773085,-8422109 },
+ { -23788118,-8254300,1950875,8937633,18686727,16459170,-905725,12376320,31632953,190926 },
+ },
+ {
+ { -24593607,-16138885,-8423991,13378746,14162407,6901328,-8288749,4508564,-25341555,-3627528 },
+ { 8884438,-5884009,6023974,10104341,-6881569,-4941533,18722941,-14786005,-1672488,827625 },
+ { -32720583,-16289296,-32503547,7101210,13354605,2659080,-1800575,-14108036,-24878478,1541286 },
+ },
+ {
+ { 2901347,-1117687,3880376,-10059388,-17620940,-3612781,-21802117,-3567481,20456845,-1885033 },
+ { 27019610,12299467,-13658288,-1603234,-12861660,-4861471,-19540150,-5016058,29439641,15138866 },
+ { 21536104,-6626420,-32447818,-10690208,-22408077,5175814,-5420040,-16361163,7779328,109896 },
+ },
+ {
+ { 30279744,14648750,-8044871,6425558,13639621,-743509,28698390,12180118,23177719,-554075 },
+ { 26572847,3405927,-31701700,12890905,-19265668,5335866,-6493768,2378492,4439158,-13279347 },
+ { -22716706,3489070,-9225266,-332753,18875722,-1140095,14819434,-12731527,-17717757,-5461437 },
+ },
+ {
+ { -5056483,16566551,15953661,3767752,-10436499,15627060,-820954,2177225,8550082,-15114165 },
+ { -18473302,16596775,-381660,15663611,22860960,15585581,-27844109,-3582739,-23260460,-8428588 },
+ { -32480551,15707275,-8205912,-5652081,29464558,2713815,-22725137,15860482,-21902570,1494193 },
+ },
+ {
+ { -19562091,-14087393,-25583872,-9299552,13127842,759709,21923482,16529112,8742704,12967017 },
+ { -28464899,1553205,32536856,-10473729,-24691605,-406174,-8914625,-2933896,-29903758,15553883 },
+ { 21877909,3230008,9881174,10539357,-4797115,2841332,11543572,14513274,19375923,-12647961 },
+ },
+ {
+ { 8832269,-14495485,13253511,5137575,5037871,4078777,24880818,-6222716,2862653,9455043 },
+ { 29306751,5123106,20245049,-14149889,9592566,8447059,-2077124,-2990080,15511449,4789663 },
+ { -20679756,7004547,8824831,-9434977,-4045704,-3750736,-5754762,108893,23513200,16652362 },
+ },
+},
+{
+ {
+ { -33256173,4144782,-4476029,-6579123,10770039,-7155542,-6650416,-12936300,-18319198,10212860 },
+ { 2756081,8598110,7383731,-6859892,22312759,-1105012,21179801,2600940,-9988298,-12506466 },
+ { -24645692,13317462,-30449259,-15653928,21365574,-10869657,11344424,864440,-2499677,-16710063 },
+ },
+ {
+ { -26432803,6148329,-17184412,-14474154,18782929,-275997,-22561534,211300,2719757,4940997 },
+ { -1323882,3911313,-6948744,14759765,-30027150,7851207,21690126,8518463,26699843,5276295 },
+ { -13149873,-6429067,9396249,365013,24703301,-10488939,1321586,149635,-15452774,7159369 },
+ },
+ {
+ { 9987780,-3404759,17507962,9505530,9731535,-2165514,22356009,8312176,22477218,-8403385 },
+ { 18155857,-16504990,19744716,9006923,15154154,-10538976,24256460,-4864995,-22548173,9334109 },
+ { 2986088,-4911893,10776628,-3473844,10620590,-7083203,-21413845,14253545,-22587149,536906 },
+ },
+ {
+ { 4377756,8115836,24567078,15495314,11625074,13064599,7390551,10589625,10838060,-15420424 },
+ { -19342404,867880,9277171,-3218459,-14431572,-1986443,19295826,-15796950,6378260,699185 },
+ { 7895026,4057113,-7081772,-13077756,-17886831,-323126,-716039,15693155,-5045064,-13373962 },
+ },
+ {
+ { -7737563,-5869402,-14566319,-7406919,11385654,13201616,31730678,-10962840,-3918636,-9669325 },
+ { 10188286,-15770834,-7336361,13427543,22223443,14896287,30743455,7116568,-21786507,5427593 },
+ { 696102,13206899,27047647,-10632082,15285305,-9853179,10798490,-4578720,19236243,12477404 },
+ },
+ {
+ { -11229439,11243796,-17054270,-8040865,-788228,-8167967,-3897669,11180504,-23169516,7733644 },
+ { 17800790,-14036179,-27000429,-11766671,23887827,3149671,23466177,-10538171,10322027,15313801 },
+ { 26246234,11968874,32263343,-5468728,6830755,-13323031,-15794704,-101982,-24449242,10890804 },
+ },
+ {
+ { -31365647,10271363,-12660625,-6267268,16690207,-13062544,-14982212,16484931,25180797,-5334884 },
+ { -586574,10376444,-32586414,-11286356,19801893,10997610,2276632,9482883,316878,13820577 },
+ { -9882808,-4510367,-2115506,16457136,-11100081,11674996,30756178,-7515054,30696930,-3712849 },
+ },
+ {
+ { 32988917,-9603412,12499366,7910787,-10617257,-11931514,-7342816,-9985397,-32349517,7392473 },
+ { -8855661,15927861,9866406,-3649411,-2396914,-16655781,-30409476,-9134995,25112947,-2926644 },
+ { -2504044,-436966,25621774,-5678772,15085042,-5479877,-24884878,-13526194,5537438,-13914319 },
+ },
+},
+{
+ {
+ { -11225584,2320285,-9584280,10149187,-33444663,5808648,-14876251,-1729667,31234590,6090599 },
+ { -9633316,116426,26083934,2897444,-6364437,-2688086,609721,15878753,-6970405,-9034768 },
+ { -27757857,247744,-15194774,-9002551,23288161,-10011936,-23869595,6503646,20650474,1804084 },
+ },
+ {
+ { -27589786,15456424,8972517,8469608,15640622,4439847,3121995,-10329713,27842616,-202328 },
+ { -15306973,2839644,22530074,10026331,4602058,5048462,28248656,5031932,-11375082,12714369 },
+ { 20807691,-7270825,29286141,11421711,-27876523,-13868230,-21227475,1035546,-19733229,12796920 },
+ },
+ {
+ { 12076899,-14301286,-8785001,-11848922,-25012791,16400684,-17591495,-12899438,3480665,-15182815 },
+ { -32361549,5457597,28548107,7833186,7303070,-11953545,-24363064,-15921875,-33374054,2771025 },
+ { -21389266,421932,26597266,6860826,22486084,-6737172,-17137485,-4210226,-24552282,15673397 },
+ },
+ {
+ { -20184622,2338216,19788685,-9620956,-4001265,-8740893,-20271184,4733254,3727144,-12934448 },
+ { 6120119,814863,-11794402,-622716,6812205,-15747771,2019594,7975683,31123697,-10958981 },
+ { 30069250,-11435332,30434654,2958439,18399564,-976289,12296869,9204260,-16432438,9648165 },
+ },
+ {
+ { 32705432,-1550977,30705658,7451065,-11805606,9631813,3305266,5248604,-26008332,-11377501 },
+ { 17219865,2375039,-31570947,-5575615,-19459679,9219903,294711,15298639,2662509,-16297073 },
+ { -1172927,-7558695,-4366770,-4287744,-21346413,-8434326,32087529,-1222777,32247248,-14389861 },
+ },
+ {
+ { 14312628,1221556,17395390,-8700143,-4945741,-8684635,-28197744,-9637817,-16027623,-13378845 },
+ { -1428825,-9678990,-9235681,6549687,-7383069,-468664,23046502,9803137,17597934,2346211 },
+ { 18510800,15337574,26171504,981392,-22241552,7827556,-23491134,-11323352,3059833,-11782870 },
+ },
+ {
+ { 10141598,6082907,17829293,-1947643,9830092,13613136,-25556636,-5544586,-33502212,3592096 },
+ { 33114168,-15889352,-26525686,-13343397,33076705,8716171,1151462,1521897,-982665,-6837803 },
+ { -32939165,-4255815,23947181,-324178,-33072974,-12305637,-16637686,3891704,26353178,693168 },
+ },
+ {
+ { 30374239,1595580,-16884039,13186931,4600344,406904,9585294,-400668,31375464,14369965 },
+ { -14370654,-7772529,1510301,6434173,-18784789,-6262728,32732230,-13108839,17901441,16011505 },
+ { 18171223,-11934626,-12500402,15197122,-11038147,-15230035,-19172240,-16046376,8764035,12309598 },
+ },
+},
+{
+ {
+ { 5975908,-5243188,-19459362,-9681747,-11541277,14015782,-23665757,1228319,17544096,-10593782 },
+ { 5811932,-1715293,3442887,-2269310,-18367348,-8359541,-18044043,-15410127,-5565381,12348900 },
+ { -31399660,11407555,25755363,6891399,-3256938,14872274,-24849353,8141295,-10632534,-585479 },
+ },
+ {
+ { -12675304,694026,-5076145,13300344,14015258,-14451394,-9698672,-11329050,30944593,1130208 },
+ { 8247766,-6710942,-26562381,-7709309,-14401939,-14648910,4652152,2488540,23550156,-271232 },
+ { 17294316,-3788438,7026748,15626851,22990044,113481,2267737,-5908146,-408818,-137719 },
+ },
+ {
+ { 16091085,-16253926,18599252,7340678,2137637,-1221657,-3364161,14550936,3260525,-7166271 },
+ { -4910104,-13332887,18550887,10864893,-16459325,-7291596,-23028869,-13204905,-12748722,2701326 },
+ { -8574695,16099415,4629974,-16340524,-20786213,-6005432,-10018363,9276971,11329923,1862132 },
+ },
+ {
+ { 14763076,-15903608,-30918270,3689867,3511892,10313526,-21951088,12219231,-9037963,-940300 },
+ { 8894987,-3446094,6150753,3013931,301220,15693451,-31981216,-2909717,-15438168,11595570 },
+ { 15214962,3537601,-26238722,-14058872,4418657,-15230761,13947276,10730794,-13489462,-4363670 },
+ },
+ {
+ { -2538306,7682793,32759013,263109,-29984731,-7955452,-22332124,-10188635,977108,699994 },
+ { -12466472,4195084,-9211532,550904,-15565337,12917920,19118110,-439841,-30534533,-14337913 },
+ { 31788461,-14507657,4799989,7372237,8808585,-14747943,9408237,-10051775,12493932,-5409317 },
+ },
+ {
+ { -25680606,5260744,-19235809,-6284470,-3695942,16566087,27218280,2607121,29375955,6024730 },
+ { 842132,-2794693,-4763381,-8722815,26332018,-12405641,11831880,6985184,-9940361,2854096 },
+ { -4847262,-7969331,2516242,-5847713,9695691,-7221186,16512645,960770,12121869,16648078 },
+ },
+ {
+ { -15218652,14667096,-13336229,2013717,30598287,-464137,-31504922,-7882064,20237806,2838411 },
+ { -19288047,4453152,15298546,-16178388,22115043,-15972604,12544294,-13470457,1068881,-12499905 },
+ { -9558883,-16518835,33238498,13506958,30505848,-1114596,-8486907,-2630053,12521378,4845654 },
+ },
+ {
+ { -28198521,10744108,-2958380,10199664,7759311,-13088600,3409348,-873400,-6482306,-12885870 },
+ { -23561822,6230156,-20382013,10655314,-24040585,-11621172,10477734,-1240216,-3113227,13974498 },
+ { 12966261,15550616,-32038948,-1615346,21025980,-629444,5642325,7188737,18895762,12629579 },
+ },
+},
+{
+ {
+ { 14741879,-14946887,22177208,-11721237,1279741,8058600,11758140,789443,32195181,3895677 },
+ { 10758205,15755439,-4509950,9243698,-4879422,6879879,-2204575,-3566119,-8982069,4429647 },
+ { -2453894,15725973,-20436342,-10410672,-5803908,-11040220,-7135870,-11642895,18047436,-15281743 },
+ },
+ {
+ { -25173001,-11307165,29759956,11776784,-22262383,-15820455,10993114,-12850837,-17620701,-9408468 },
+ { 21987233,700364,-24505048,14972008,-7774265,-5718395,32155026,2581431,-29958985,8773375 },
+ { -25568350,454463,-13211935,16126715,25240068,8594567,20656846,12017935,-7874389,-13920155 },
+ },
+ {
+ { 6028182,6263078,-31011806,-11301710,-818919,2461772,-31841174,-5468042,-1721788,-2776725 },
+ { -12278994,16624277,987579,-5922598,32908203,1248608,7719845,-4166698,28408820,6816612 },
+ { -10358094,-8237829,19549651,-12169222,22082623,16147817,20613181,13982702,-10339570,5067943 },
+ },
+ {
+ { -30505967,-3821767,12074681,13582412,-19877972,2443951,-19719286,12746132,5331210,-10105944 },
+ { 30528811,3601899,-1957090,4619785,-27361822,-15436388,24180793,-12570394,27679908,-1648928 },
+ { 9402404,-13957065,32834043,10838634,-26580150,-13237195,26653274,-8685565,22611444,-12715406 },
+ },
+ {
+ { 22190590,1118029,22736441,15130463,-30460692,-5991321,19189625,-4648942,4854859,6622139 },
+ { -8310738,-2953450,-8262579,-3388049,-10401731,-271929,13424426,-3567227,26404409,13001963 },
+ { -31241838,-15415700,-2994250,8939346,11562230,-12840670,-26064365,-11621720,-15405155,11020693 },
+ },
+ {
+ { 1866042,-7949489,-7898649,-10301010,12483315,13477547,3175636,-12424163,28761762,1406734 },
+ { -448555,-1777666,13018551,3194501,-9580420,-11161737,24760585,-4347088,25577411,-13378680 },
+ { -24290378,4759345,-690653,-1852816,2066747,10693769,-29595790,9884936,-9368926,4745410 },
+ },
+ {
+ { -9141284,6049714,-19531061,-4341411,-31260798,9944276,-15462008,-11311852,10931924,-11931931 },
+ { -16561513,14112680,-8012645,4817318,-8040464,-11414606,-22853429,10856641,-20470770,13434654 },
+ { 22759489,-10073434,-16766264,-1871422,13637442,-10168091,1765144,-12654326,28445307,-5364710 },
+ },
+ {
+ { 29875063,12493613,2795536,-3786330,1710620,15181182,-10195717,-8788675,9074234,1167180 },
+ { -26205683,11014233,-9842651,-2635485,-26908120,7532294,-18716888,-9535498,3843903,9367684 },
+ { -10969595,-6403711,9591134,9582310,11349256,108879,16235123,8601684,-139197,4242895 },
+ },
+},
+{
+ {
+ { 22092954,-13191123,-2042793,-11968512,32186753,-11517388,-6574341,2470660,-27417366,16625501 },
+ { -11057722,3042016,13770083,-9257922,584236,-544855,-7770857,2602725,-27351616,14247413 },
+ { 6314175,-10264892,-32772502,15957557,-10157730,168750,-8618807,14290061,27108877,-1180880 },
+ },
+ {
+ { -8586597,-7170966,13241782,10960156,-32991015,-13794596,33547976,-11058889,-27148451,981874 },
+ { 22833440,9293594,-32649448,-13618667,-9136966,14756819,-22928859,-13970780,-10479804,-16197962 },
+ { -7768587,3326786,-28111797,10783824,19178761,14905060,22680049,13906969,-15933690,3797899 },
+ },
+ {
+ { 21721356,-4212746,-12206123,9310182,-3882239,-13653110,23740224,-2709232,20491983,-8042152 },
+ { 9209270,-15135055,-13256557,-6167798,-731016,15289673,25947805,15286587,30997318,-6703063 },
+ { 7392032,16618386,23946583,-8039892,-13265164,-1533858,-14197445,-2321576,17649998,-250080 },
+ },
+ {
+ { -9301088,-14193827,30609526,-3049543,-25175069,-1283752,-15241566,-9525724,-2233253,7662146 },
+ { -17558673,1763594,-33114336,15908610,-30040870,-12174295,7335080,-8472199,-3174674,3440183 },
+ { -19889700,-5977008,-24111293,-9688870,10799743,-16571957,40450,-4431835,4862400,1133 },
+ },
+ {
+ { -32856209,-7873957,-5422389,14860950,-16319031,7956142,7258061,311861,-30594991,-7379421 },
+ { -3773428,-1565936,28985340,7499440,24445838,9325937,29727763,16527196,18278453,15405622 },
+ { -4381906,8508652,-19898366,-3674424,-5984453,15149970,-13313598,843523,-21875062,13626197 },
+ },
+ {
+ { 2281448,-13487055,-10915418,-2609910,1879358,16164207,-10783882,3953792,13340839,15928663 },
+ { 31727126,-7179855,-18437503,-8283652,2875793,-16390330,-25269894,-7014826,-23452306,5964753 },
+ { 4100420,-5959452,-17179337,6017714,-18705837,12227141,-26684835,11344144,2538215,-7570755 },
+ },
+ {
+ { -9433605,6123113,11159803,-2156608,30016280,14966241,-20474983,1485421,-629256,-15958862 },
+ { -26804558,4260919,11851389,9658551,-32017107,16367492,-20205425,-13191288,11659922,-11115118 },
+ { 26180396,10015009,-30844224,-8581293,5418197,9480663,2231568,-10170080,33100372,-1306171 },
+ },
+ {
+ { 15121113,-5201871,-10389905,15427821,-27509937,-15992507,21670947,4486675,-5931810,-14466380 },
+ { 16166486,-9483733,-11104130,6023908,-31926798,-1364923,2340060,-16254968,-10735770,-10039824 },
+ { 28042865,-3557089,-12126526,12259706,-3717498,-6945899,6766453,-8689599,18036436,5803270 },
+ },
+},
+{
+ {
+ { -817581,6763912,11803561,1585585,10958447,-2671165,23855391,4598332,-6159431,-14117438 },
+ { -31031306,-14256194,17332029,-2383520,31312682,-5967183,696309,50292,-20095739,11763584 },
+ { -594563,-2514283,-32234153,12643980,12650761,14811489,665117,-12613632,-19773211,-10713562 },
+ },
+ {
+ { 30464590,-11262872,-4127476,-12734478,19835327,-7105613,-24396175,2075773,-17020157,992471 },
+ { 18357185,-6994433,7766382,16342475,-29324918,411174,14578841,8080033,-11574335,-10601610 },
+ { 19598397,10334610,12555054,2555664,18821899,-10339780,21873263,16014234,26224780,16452269 },
+ },
+ {
+ { -30223925,5145196,5944548,16385966,3976735,2009897,-11377804,-7618186,-20533829,3698650 },
+ { 14187449,3448569,-10636236,-10810935,-22663880,-3433596,7268410,-10890444,27394301,12015369 },
+ { 19695761,16087646,28032085,12999827,6817792,11427614,20244189,-1312777,-13259127,-3402461 },
+ },
+ {
+ { 30860103,12735208,-1888245,-4699734,-16974906,2256940,-8166013,12298312,-8550524,-10393462 },
+ { -5719826,-11245325,-1910649,15569035,26642876,-7587760,-5789354,-15118654,-4976164,12651793 },
+ { -2848395,9953421,11531313,-5282879,26895123,-12697089,-13118820,-16517902,9768698,-2533218 },
+ },
+ {
+ { -24719459,1894651,-287698,-4704085,15348719,-8156530,32767513,12765450,4940095,10678226 },
+ { 18860224,15980149,-18987240,-1562570,-26233012,-11071856,-7843882,13944024,-24372348,16582019 },
+ { -15504260,4970268,-29893044,4175593,-20993212,-2199756,-11704054,15444560,-11003761,7989037 },
+ },
+ {
+ { 31490452,5568061,-2412803,2182383,-32336847,4531686,-32078269,6200206,-19686113,-14800171 },
+ { -17308668,-15879940,-31522777,-2831,-32887382,16375549,8680158,-16371713,28550068,-6857132 },
+ { -28126887,-5688091,16837845,-1820458,-6850681,12700016,-30039981,4364038,1155602,5988841 },
+ },
+ {
+ { 21890435,-13272907,-12624011,12154349,-7831873,15300496,23148983,-4470481,24618407,8283181 },
+ { -33136107,-10512751,9975416,6841041,-31559793,16356536,3070187,-7025928,1466169,10740210 },
+ { -1509399,-15488185,-13503385,-10655916,32799044,909394,-13938903,-5779719,-32164649,-15327040 },
+ },
+ {
+ { 3960823,-14267803,-28026090,-15918051,-19404858,13146868,15567327,951507,-3260321,-573935 },
+ { 24740841,5052253,-30094131,8961361,25877428,6165135,-24368180,14397372,-7380369,-6144105 },
+ { -28888365,3510803,-28103278,-1158478,-11238128,-10631454,-15441463,-14453128,-1625486,-6494814 },
+ },
+},
+{
+ {
+ { 793299,-9230478,8836302,-6235707,-27360908,-2369593,33152843,-4885251,-9906200,-621852 },
+ { 5666233,525582,20782575,-8038419,-24538499,14657740,16099374,1468826,-6171428,-15186581 },
+ { -4859255,-3779343,-2917758,-6748019,7778750,11688288,-30404353,-9871238,-1558923,-9863646 },
+ },
+ {
+ { 10896332,-7719704,824275,472601,-19460308,3009587,25248958,14783338,-30581476,-15757844 },
+ { 10566929,12612572,-31944212,11118703,-12633376,12362879,21752402,8822496,24003793,14264025 },
+ { 27713862,-7355973,-11008240,9227530,27050101,2504721,23886875,-13117525,13958495,-5732453 },
+ },
+ {
+ { -23481610,4867226,-27247128,3900521,29838369,-8212291,-31889399,-10041781,7340521,-15410068 },
+ { 4646514,-8011124,-22766023,-11532654,23184553,8566613,31366726,-1381061,-15066784,-10375192 },
+ { -17270517,12723032,-16993061,14878794,21619651,-6197576,27584817,3093888,-8843694,3849921 },
+ },
+ {
+ { -9064912,2103172,25561640,-15125738,-5239824,9582958,32477045,-9017955,5002294,-15550259 },
+ { -12057553,-11177906,21115585,-13365155,8808712,-12030708,16489530,13378448,-25845716,12741426 },
+ { -5946367,10645103,-30911586,15390284,-3286982,-7118677,24306472,15852464,28834118,-7646072 },
+ },
+ {
+ { -17335748,-9107057,-24531279,9434953,-8472084,-583362,-13090771,455841,20461858,5491305 },
+ { 13669248,-16095482,-12481974,-10203039,-14569770,-11893198,-24995986,11293807,-28588204,-9421832 },
+ { 28497928,6272777,-33022994,14470570,8906179,-1225630,18504674,-14165166,29867745,-8795943 },
+ },
+ {
+ { -16207023,13517196,-27799630,-13697798,24009064,-6373891,-6367600,-13175392,22853429,-4012011 },
+ { 24191378,16712145,-13931797,15217831,14542237,1646131,18603514,-11037887,12876623,-2112447 },
+ { 17902668,4518229,-411702,-2829247,26878217,5258055,-12860753,608397,16031844,3723494 },
+ },
+ {
+ { -28632773,12763728,-20446446,7577504,33001348,-13017745,17558842,-7872890,23896954,-4314245 },
+ { -20005381,-12011952,31520464,605201,2543521,5991821,-2945064,7229064,-9919646,-8826859 },
+ { 28816045,298879,-28165016,-15920938,19000928,-1665890,-12680833,-2949325,-18051778,-2082915 },
+ },
+ {
+ { 16000882,-344896,3493092,-11447198,-29504595,-13159789,12577740,16041268,-19715240,7847707 },
+ { 10151868,10572098,27312476,7922682,14825339,4723128,-32855931,-6519018,-10020567,3852848 },
+ { -11430470,15697596,-21121557,-4420647,5386314,15063598,16514493,-15932110,29330899,-15076224 },
+ },
+},
+{
+ {
+ { -25499735,-4378794,-15222908,-6901211,16615731,2051784,3303702,15490,-27548796,12314391 },
+ { 15683520,-6003043,18109120,-9980648,15337968,-5997823,-16717435,15921866,16103996,-3731215 },
+ { -23169824,-10781249,13588192,-1628807,-3798557,-1074929,-19273607,5402699,-29815713,-9841101 },
+ },
+ {
+ { 23190676,2384583,-32714340,3462154,-29903655,-1529132,-11266856,8911517,-25205859,2739713 },
+ { 21374101,-3554250,-33524649,9874411,15377179,11831242,-33529904,6134907,4931255,11987849 },
+ { -7732,-2978858,-16223486,7277597,105524,-322051,-31480539,13861388,-30076310,10117930 },
+ },
+ {
+ { -29501170,-10744872,-26163768,13051539,-25625564,5089643,-6325503,6704079,12890019,15728940 },
+ { -21972360,-11771379,-951059,-4418840,14704840,2695116,903376,-10428139,12885167,8311031 },
+ { -17516482,5352194,10384213,-13811658,7506451,13453191,26423267,4384730,1888765,-5435404 },
+ },
+ {
+ { -25817338,-3107312,-13494599,-3182506,30896459,-13921729,-32251644,-12707869,-19464434,-3340243 },
+ { -23607977,-2665774,-526091,4651136,5765089,4618330,6092245,14845197,17151279,-9854116 },
+ { -24830458,-12733720,-15165978,10367250,-29530908,-265356,22825805,-7087279,-16866484,16176525 },
+ },
+ {
+ { -23583256,6564961,20063689,3798228,-4740178,7359225,2006182,-10363426,-28746253,-10197509 },
+ { -10626600,-4486402,-13320562,-5125317,3432136,-6393229,23632037,-1940610,32808310,1099883 },
+ { 15030977,5768825,-27451236,-2887299,-6427378,-15361371,-15277896,-6809350,2051441,-15225865 },
+ },
+ {
+ { -3362323,-7239372,7517890,9824992,23555850,295369,5148398,-14154188,-22686354,16633660 },
+ { 4577086,-16752288,13249841,-15304328,19958763,-14537274,18559670,-10759549,8402478,-9864273 },
+ { -28406330,-1051581,-26790155,-907698,-17212414,-11030789,9453451,-14980072,17983010,9967138 },
+ },
+ {
+ { -25762494,6524722,26585488,9969270,24709298,1220360,-1677990,7806337,17507396,3651560 },
+ { -10420457,-4118111,14584639,15971087,-15768321,8861010,26556809,-5574557,-18553322,-11357135 },
+ { 2839101,14284142,4029895,3472686,14402957,12689363,-26642121,8459447,-5605463,-7621941 },
+ },
+ {
+ { -4839289,-3535444,9744961,2871048,25113978,3187018,-25110813,-849066,17258084,-7977739 },
+ { 18164541,-10595176,-17154882,-1542417,19237078,-9745295,23357533,-15217008,26908270,12150756 },
+ { -30264870,-7647865,5112249,-7036672,-1499807,-6974257,43168,-5537701,-32302074,16215819 },
+ },
+},
+{
+ {
+ { -6898905,9824394,-12304779,-4401089,-31397141,-6276835,32574489,12532905,-7503072,-8675347 },
+ { -27343522,-16515468,-27151524,-10722951,946346,16291093,254968,7168080,21676107,-1943028 },
+ { 21260961,-8424752,-16831886,-11920822,-23677961,3968121,-3651949,-6215466,-3556191,-7913075 },
+ },
+ {
+ { 16544754,13250366,-16804428,15546242,-4583003,12757258,-2462308,-8680336,-18907032,-9662799 },
+ { -2415239,-15577728,18312303,4964443,-15272530,-12653564,26820651,16690659,25459437,-4564609 },
+ { -25144690,11425020,28423002,-11020557,-6144921,-15826224,9142795,-2391602,-6432418,-1644817 },
+ },
+ {
+ { -23104652,6253476,16964147,-3768872,-25113972,-12296437,-27457225,-16344658,6335692,7249989 },
+ { -30333227,13979675,7503222,-12368314,-11956721,-4621693,-30272269,2682242,25993170,-12478523 },
+ { 4364628,5930691,32304656,-10044554,-8054781,15091131,22857016,-10598955,31820368,15075278 },
+ },
+ {
+ { 31879134,-8918693,17258761,90626,-8041836,-4917709,24162788,-9650886,-17970238,12833045 },
+ { 19073683,14851414,-24403169,-11860168,7625278,11091125,-19619190,2074449,-9413939,14905377 },
+ { 24483667,-11935567,-2518866,-11547418,-1553130,15355506,-25282080,9253129,27628530,-7555480 },
+ },
+ {
+ { 17597607,8340603,19355617,552187,26198470,-3176583,4593324,-9157582,-14110875,15297016 },
+ { 510886,14337390,-31785257,16638632,6328095,2713355,-20217417,-11864220,8683221,2921426 },
+ { 18606791,11874196,27155355,-5281482,-24031742,6265446,-25178240,-1278924,4674690,13890525 },
+ },
+ {
+ { 13609624,13069022,-27372361,-13055908,24360586,9592974,14977157,9835105,4389687,288396 },
+ { 9922506,-519394,13613107,5883594,-18758345,-434263,-12304062,8317628,23388070,16052080 },
+ { 12720016,11937594,-31970060,-5028689,26900120,8561328,-20155687,-11632979,-14754271,-10812892 },
+ },
+ {
+ { 15961858,14150409,26716931,-665832,-22794328,13603569,11829573,7467844,-28822128,929275 },
+ { 11038231,-11582396,-27310482,-7316562,-10498527,-16307831,-23479533,-9371869,-21393143,2465074 },
+ { 20017163,-4323226,27915242,1529148,12396362,15675764,13817261,-9658066,2463391,-4622140 },
+ },
+ {
+ { -16358878,-12663911,-12065183,4996454,-1256422,1073572,9583558,12851107,4003896,12673717 },
+ { -1731589,-15155870,-3262930,16143082,19294135,13385325,14741514,-9103726,7903886,2348101 },
+ { 24536016,-16515207,12715592,-3862155,1511293,10047386,-3842346,-7129159,-28377538,10048127 },
+ },
+},
+{
+ {
+ { -12622226,-6204820,30718825,2591312,-10617028,12192840,18873298,-7297090,-32297756,15221632 },
+ { -26478122,-11103864,11546244,-1852483,9180880,7656409,-21343950,2095755,29769758,6593415 },
+ { -31994208,-2907461,4176912,3264766,12538965,-868111,26312345,-6118678,30958054,8292160 },
+ },
+ {
+ { 31429822,-13959116,29173532,15632448,12174511,-2760094,32808831,3977186,26143136,-3148876 },
+ { 22648901,1402143,-22799984,13746059,7936347,365344,-8668633,-1674433,-3758243,-2304625 },
+ { -15491917,8012313,-2514730,-12702462,-23965846,-10254029,-1612713,-1535569,-16664475,8194478 },
+ },
+ {
+ { 27338066,-7507420,-7414224,10140405,-19026427,-6589889,27277191,8855376,28572286,3005164 },
+ { 26287124,4821776,25476601,-4145903,-3764513,-15788984,-18008582,1182479,-26094821,-13079595 },
+ { -7171154,3178080,23970071,6201893,-17195577,-4489192,-21876275,-13982627,32208683,-1198248 },
+ },
+ {
+ { -16657702,2817643,-10286362,14811298,6024667,13349505,-27315504,-10497842,-27672585,-11539858 },
+ { 15941029,-9405932,-21367050,8062055,31876073,-238629,-15278393,-1444429,15397331,-4130193 },
+ { 8934485,-13485467,-23286397,-13423241,-32446090,14047986,31170398,-1441021,-27505566,15087184 },
+ },
+ {
+ { -18357243,-2156491,24524913,-16677868,15520427,-6360776,-15502406,11461896,16788528,-5868942 },
+ { -1947386,16013773,21750665,3714552,-17401782,-16055433,-3770287,-10323320,31322514,-11615635 },
+ { 21426655,-5650218,-13648287,-5347537,-28812189,-4920970,-18275391,-14621414,13040862,-12112948 },
+ },
+ {
+ { 11293895,12478086,-27136401,15083750,-29307421,14748872,14555558,-13417103,1613711,4896935 },
+ { -25894883,15323294,-8489791,-8057900,25967126,-13425460,2825960,-4897045,-23971776,-11267415 },
+ { -15924766,-5229880,-17443532,6410664,3622847,10243618,20615400,12405433,-23753030,-8436416 },
+ },
+ {
+ { -7091295,12556208,-20191352,9025187,-17072479,4333801,4378436,2432030,23097949,-566018 },
+ { 4565804,-16025654,20084412,-7842817,1724999,189254,24767264,10103221,-18512313,2424778 },
+ { 366633,-11976806,8173090,-6890119,30788634,5745705,-7168678,1344109,-3642553,12412659 },
+ },
+ {
+ { -24001791,7690286,14929416,-168257,-32210835,-13412986,24162697,-15326504,-3141501,11179385 },
+ { 18289522,-14724954,8056945,16430056,-21729724,7842514,-6001441,-1486897,-18684645,-11443503 },
+ { 476239,6601091,-6152790,-9723375,17503545,-4863900,27672959,13403813,11052904,5219329 },
+ },
+},
+{
+ {
+ { 20678546,-8375738,-32671898,8849123,-5009758,14574752,31186971,-3973730,9014762,-8579056 },
+ { -13644050,-10350239,-15962508,5075808,-1514661,-11534600,-33102500,9160280,8473550,-3256838 },
+ { 24900749,14435722,17209120,-15292541,-22592275,9878983,-7689309,-16335821,-24568481,11788948 },
+ },
+ {
+ { -3118155,-11395194,-13802089,14797441,9652448,-6845904,-20037437,10410733,-24568470,-1458691 },
+ { -15659161,16736706,-22467150,10215878,-9097177,7563911,11871841,-12505194,-18513325,8464118 },
+ { -23400612,8348507,-14585951,-861714,-3950205,-6373419,14325289,8628612,33313881,-8370517 },
+ },
+ {
+ { -20186973,-4967935,22367356,5271547,-1097117,-4788838,-24805667,-10236854,-8940735,-5818269 },
+ { -6948785,-1795212,-32625683,-16021179,32635414,-7374245,15989197,-12838188,28358192,-4253904 },
+ { -23561781,-2799059,-32351682,-1661963,-9147719,10429267,-16637684,4072016,-5351664,5596589 },
+ },
+ {
+ { -28236598,-3390048,12312896,6213178,3117142,16078565,29266239,2557221,1768301,15373193 },
+ { -7243358,-3246960,-4593467,-7553353,-127927,-912245,-1090902,-4504991,-24660491,3442910 },
+ { -30210571,5124043,14181784,8197961,18964734,-11939093,22597931,7176455,-18585478,13365930 },
+ },
+ {
+ { -7877390,-1499958,8324673,4690079,6261860,890446,24538107,-8570186,-9689599,-3031667 },
+ { 25008904,-10771599,-4305031,-9638010,16265036,15721635,683793,-11823784,15723479,-15163481 },
+ { -9660625,12374379,-27006999,-7026148,-7724114,-12314514,11879682,5400171,519526,-1235876 },
+ },
+ {
+ { 22258397,-16332233,-7869817,14613016,-22520255,-2950923,-20353881,7315967,16648397,7605640 },
+ { -8081308,-8464597,-8223311,9719710,19259459,-15348212,23994942,-5281555,-9468848,4763278 },
+ { -21699244,9220969,-15730624,1084137,-25476107,-2852390,31088447,-7764523,-11356529,728112 },
+ },
+ {
+ { 26047220,-11751471,-6900323,-16521798,24092068,9158119,-4273545,-12555558,-29365436,-5498272 },
+ { 17510331,-322857,5854289,8403524,17133918,-3112612,-28111007,12327945,10750447,10014012 },
+ { -10312768,3936952,9156313,-8897683,16498692,-994647,-27481051,-666732,3424691,7540221 },
+ },
+ {
+ { 30322361,-6964110,11361005,-4143317,7433304,4989748,-7071422,-16317219,-9244265,15258046 },
+ { 13054562,-2779497,19155474,469045,-12482797,4566042,5631406,2711395,1062915,-5136345 },
+ { -19240248,-11254599,-29509029,-7499965,-5835763,13005411,-6066489,12194497,32960380,1459310 },
+ },
+},
+{
+ {
+ { 19852034,7027924,23669353,10020366,8586503,-6657907,394197,-6101885,18638003,-11174937 },
+ { 31395534,15098109,26581030,8030562,-16527914,-5007134,9012486,-7584354,-6643087,-5442636 },
+ { -9192165,-2347377,-1997099,4529534,25766844,607986,-13222,9677543,-32294889,-6456008 },
+ },
+ {
+ { -2444496,-149937,29348902,8186665,1873760,12489863,-30934579,-7839692,-7852844,-8138429 },
+ { -15236356,-15433509,7766470,746860,26346930,-10221762,-27333451,10754588,-9431476,5203576 },
+ { 31834314,14135496,-770007,5159118,20917671,-16768096,-7467973,-7337524,31809243,7347066 },
+ },
+ {
+ { -9606723,-11874240,20414459,13033986,13716524,-11691881,19797970,-12211255,15192876,-2087490 },
+ { -12663563,-2181719,1168162,-3804809,26747877,-14138091,10609330,12694420,33473243,-13382104 },
+ { 33184999,11180355,15832085,-11385430,-1633671,225884,15089336,-11023903,-6135662,14480053 },
+ },
+ {
+ { 31308717,-5619998,31030840,-1897099,15674547,-6582883,5496208,13685227,27595050,8737275 },
+ { -20318852,-15150239,10933843,-16178022,8335352,-7546022,-31008351,-12610604,26498114,66511 },
+ { 22644454,-8761729,-16671776,4884562,-3105614,-13559366,30540766,-4286747,-13327787,-7515095 },
+ },
+ {
+ { -28017847,9834845,18617207,-2681312,-3401956,-13307506,8205540,13585437,-17127465,15115439 },
+ { 23711543,-672915,31206561,-8362711,6164647,-9709987,-33535882,-1426096,8236921,16492939 },
+ { -23910559,-13515526,-26299483,-4503841,25005590,-7687270,19574902,10071562,6708380,-6222424 },
+ },
+ {
+ { 2101391,-4930054,19702731,2367575,-15427167,1047675,5301017,9328700,29955601,-11678310 },
+ { 3096359,9271816,-21620864,-15521844,-14847996,-7592937,-25892142,-12635595,-9917575,6216608 },
+ { -32615849,338663,-25195611,2510422,-29213566,-13820213,24822830,-6146567,-26767480,7525079 },
+ },
+ {
+ { -23066649,-13985623,16133487,-7896178,-3389565,778788,-910336,-2782495,-19386633,11994101 },
+ { 21691500,-13624626,-641331,-14367021,3285881,-3483596,-25064666,9718258,-7477437,13381418 },
+ { 18445390,-4202236,14979846,11622458,-1727110,-3582980,23111648,-6375247,28535282,15779576 },
+ },
+ {
+ { 30098053,3089662,-9234387,16662135,-21306940,11308411,-14068454,12021730,9955285,-16303356 },
+ { 9734894,-14576830,-7473633,-9138735,2060392,11313496,-18426029,9924399,20194861,13380996 },
+ { -26378102,-7965207,-22167821,15789297,-18055342,-6168792,-1984914,15707771,26342023,10146099 },
+ },
+},
+{
+ {
+ { -26016874,-219943,21339191,-41388,19745256,-2878700,-29637280,2227040,21612326,-545728 },
+ { -13077387,1184228,23562814,-5970442,-20351244,-6348714,25764461,12243797,-20856566,11649658 },
+ { -10031494,11262626,27384172,2271902,26947504,-15997771,39944,6114064,33514190,2333242 },
+ },
+ {
+ { -21433588,-12421821,8119782,7219913,-21830522,-9016134,-6679750,-12670638,24350578,-13450001 },
+ { -4116307,-11271533,-23886186,4843615,-30088339,690623,-31536088,-10406836,8317860,12352766 },
+ { 18200138,-14475911,-33087759,-2696619,-23702521,-9102511,-23552096,-2287550,20712163,6719373 },
+ },
+ {
+ { 26656208,6075253,-7858556,1886072,-28344043,4262326,11117530,-3763210,26224235,-3297458 },
+ { -17168938,-14854097,-3395676,-16369877,-19954045,14050420,21728352,9493610,18620611,-16428628 },
+ { -13323321,13325349,11432106,5964811,18609221,6062965,-5269471,-9725556,-30701573,-16479657 },
+ },
+ {
+ { -23860538,-11233159,26961357,1640861,-32413112,-16737940,12248509,-5240639,13735342,1934062 },
+ { 25089769,6742589,17081145,-13406266,21909293,-16067981,-15136294,-3765346,-21277997,5473616 },
+ { 31883677,-7961101,1083432,-11572403,22828471,13290673,-7125085,12469656,29111212,-5451014 },
+ },
+ {
+ { 24244947,-15050407,-26262976,2791540,-14997599,16666678,24367466,6388839,-10295587,452383 },
+ { -25640782,-3417841,5217916,16224624,19987036,-4082269,-24236251,-5915248,15766062,8407814 },
+ { -20406999,13990231,15495425,16395525,5377168,15166495,-8917023,-4388953,-8067909,2276718 },
+ },
+ {
+ { 30157918,12924066,-17712050,9245753,19895028,3368142,-23827587,5096219,22740376,-7303417 },
+ { 2041139,-14256350,7783687,13876377,-25946985,-13352459,24051124,13742383,-15637599,13295222 },
+ { 33338237,-8505733,12532113,7977527,9106186,-1715251,-17720195,-4612972,-4451357,-14669444 },
+ },
+ {
+ { -20045281,5454097,-14346548,6447146,28862071,1883651,-2469266,-4141880,7770569,9620597 },
+ { 23208068,7979712,33071466,8149229,1758231,-10834995,30945528,-1694323,-33502340,-14767970 },
+ { 1439958,-16270480,-1079989,-793782,4625402,10647766,-5043801,1220118,30494170,-11440799 },
+ },
+ {
+ { -5037580,-13028295,-2970559,-3061767,15640974,-6701666,-26739026,926050,-1684339,-13333647 },
+ { 13908495,-3549272,30919928,-6273825,-21521863,7989039,9021034,9078865,3353509,4033511 },
+ { -29663431,-15113610,32259991,-344482,24295849,-12912123,23161163,8839127,27485041,7356032 },
+ },
+},
+{
+ {
+ { 9661027,705443,11980065,-5370154,-1628543,14661173,-6346142,2625015,28431036,-16771834 },
+ { -23839233,-8311415,-25945511,7480958,-17681669,-8354183,-22545972,14150565,15970762,4099461 },
+ { 29262576,16756590,26350592,-8793563,8529671,-11208050,13617293,-9937143,11465739,8317062 },
+ },
+ {
+ { -25493081,-6962928,32500200,-9419051,-23038724,-2302222,14898637,3848455,20969334,-5157516 },
+ { -20384450,-14347713,-18336405,13884722,-33039454,2842114,-21610826,-3649888,11177095,14989547 },
+ { -24496721,-11716016,16959896,2278463,12066309,10137771,13515641,2581286,-28487508,9930240 },
+ },
+ {
+ { -17751622,-2097826,16544300,-13009300,-15914807,-14949081,18345767,-13403753,16291481,-5314038 },
+ { -33229194,2553288,32678213,9875984,8534129,6889387,-9676774,6957617,4368891,9788741 },
+ { 16660756,7281060,-10830758,12911820,20108584,-8101676,-21722536,-8613148,16250552,-11111103 },
+ },
+ {
+ { -19765507,2390526,-16551031,14161980,1905286,6414907,4689584,10604807,-30190403,4782747 },
+ { -1354539,14736941,-7367442,-13292886,7710542,-14155590,-9981571,4383045,22546403,437323 },
+ { 31665577,-12180464,-16186830,1491339,-18368625,3294682,27343084,2786261,-30633590,-14097016 },
+ },
+ {
+ { -14467279,-683715,-33374107,7448552,19294360,14334329,-19690631,2355319,-19284671,-6114373 },
+ { 15121312,-15796162,6377020,-6031361,-10798111,-12957845,18952177,15496498,-29380133,11754228 },
+ { -2637277,-13483075,8488727,-14303896,12728761,-1622493,7141596,11724556,22761615,-10134141 },
+ },
+ {
+ { 16918416,11729663,-18083579,3022987,-31015732,-13339659,-28741185,-12227393,32851222,11717399 },
+ { 11166634,7338049,-6722523,4531520,-29468672,-7302055,31474879,3483633,-1193175,-4030831 },
+ { -185635,9921305,31456609,-13536438,-12013818,13348923,33142652,6546660,-19985279,-3948376 },
+ },
+ {
+ { -32460596,11266712,-11197107,-7899103,31703694,3855903,-8537131,-12833048,-30772034,-15486313 },
+ { -18006477,12709068,3991746,-6479188,-21491523,-10550425,-31135347,-16049879,10928917,3011958 },
+ { -6957757,-15594337,31696059,334240,29576716,14796075,-30831056,-12805180,18008031,10258577 },
+ },
+ {
+ { -22448644,15655569,7018479,-4410003,-30314266,-1201591,-1853465,1367120,25127874,6671743 },
+ { 29701166,-14373934,-10878120,9279288,-17568,13127210,21382910,11042292,25838796,4642684 },
+ { -20430234,14955537,-24126347,8124619,-5369288,-5990470,30468147,-13900640,18423289,4177476 },
+ },
+},
diff --git a/plugin/auth_ed25519/ref10/base2.h b/plugin/auth_ed25519/ref10/base2.h
new file mode 100644
index 00000000..8c538440
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/base2.h
@@ -0,0 +1,40 @@
+ {
+ { 25967493,-14356035,29566456,3660896,-12694345,4014787,27544626,-11754271,-6079156,2047605 },
+ { -12545711,934262,-2722910,3049990,-727428,9406986,12720692,5043384,19500929,-15469378 },
+ { -8738181,4489570,9688441,-14785194,10184609,-12363380,29287919,11864899,-24514362,-4438546 },
+ },
+ {
+ { 15636291,-9688557,24204773,-7912398,616977,-16685262,27787600,-14772189,28944400,-1550024 },
+ { 16568933,4717097,-11556148,-1102322,15682896,-11807043,16354577,-11775962,7689662,11199574 },
+ { 30464156,-5976125,-11779434,-15670865,23220365,15915852,7512774,10017326,-17749093,-9920357 },
+ },
+ {
+ { 10861363,11473154,27284546,1981175,-30064349,12577861,32867885,14515107,-15438304,10819380 },
+ { 4708026,6336745,20377586,9066809,-11272109,6594696,-25653668,12483688,-12668491,5581306 },
+ { 19563160,16186464,-29386857,4097519,10237984,-4348115,28542350,13850243,-23678021,-15815942 },
+ },
+ {
+ { 5153746,9909285,1723747,-2777874,30523605,5516873,19480852,5230134,-23952439,-15175766 },
+ { -30269007,-3463509,7665486,10083793,28475525,1649722,20654025,16520125,30598449,7715701 },
+ { 28881845,14381568,9657904,3680757,-20181635,7843316,-31400660,1370708,29794553,-1409300 },
+ },
+ {
+ { -22518993,-6692182,14201702,-8745502,-23510406,8844726,18474211,-1361450,-13062696,13821877 },
+ { -6455177,-7839871,3374702,-4740862,-27098617,-10571707,31655028,-7212327,18853322,-14220951 },
+ { 4566830,-12963868,-28974889,-12240689,-7602672,-2830569,-8514358,-10431137,2207753,-3209784 },
+ },
+ {
+ { -25154831,-4185821,29681144,7868801,-6854661,-9423865,-12437364,-663000,-31111463,-16132436 },
+ { 25576264,-2703214,7349804,-11814844,16472782,9300885,3844789,15725684,171356,6466918 },
+ { 23103977,13316479,9739013,-16149481,817875,-15038942,8965339,-14088058,-30714912,16193877 },
+ },
+ {
+ { -33521811,3180713,-2394130,14003687,-16903474,-16270840,17238398,4729455,-18074513,9256800 },
+ { -25182317,-4174131,32336398,5036987,-21236817,11360617,22616405,9761698,-19827198,630305 },
+ { -13720693,2639453,-24237460,-7406481,9494427,-5774029,-6554551,-15960994,-2449256,-14291300 },
+ },
+ {
+ { -3151181,-5046075,9282714,6866145,-31907062,-863023,-18940575,15033784,25105118,-7894876 },
+ { -24326370,15950226,-31801215,-14592823,-11662737,-5090925,1573892,-2625887,2198790,-15804619 },
+ { -3099351,10324967,-2241613,7453183,-5446979,-2735503,-13812022,-16236442,-32461234,-12290683 },
+ },
diff --git a/plugin/auth_ed25519/ref10/d.h b/plugin/auth_ed25519/ref10/d.h
new file mode 100644
index 00000000..e25f5783
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/d.h
@@ -0,0 +1 @@
+-10913610,13857413,-15372611,6949391,114729,-8787816,-6275908,-3247719,-18696448,-12055116
diff --git a/plugin/auth_ed25519/ref10/d2.h b/plugin/auth_ed25519/ref10/d2.h
new file mode 100644
index 00000000..01aaec75
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/d2.h
@@ -0,0 +1 @@
+-21827239,-5839606,-30745221,13898782,229458,15978800,-12551817,-6495438,29715968,9444199
diff --git a/plugin/auth_ed25519/ref10/fe.h b/plugin/auth_ed25519/ref10/fe.h
new file mode 100644
index 00000000..60c308ba
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe.h
@@ -0,0 +1,56 @@
+#ifndef FE_H
+#define FE_H
+
+#include "crypto_int32.h"
+
+typedef crypto_int32 fe[10];
+
+/*
+fe means field element.
+Here the field is \Z/(2^255-19).
+An element t, entries t[0]...t[9], represents the integer
+t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9].
+Bounds on each t[i] vary depending on context.
+*/
+
+#define fe_frombytes crypto_sign_ed25519_ref10_fe_frombytes
+#define fe_tobytes crypto_sign_ed25519_ref10_fe_tobytes
+#define fe_copy crypto_sign_ed25519_ref10_fe_copy
+#define fe_isnonzero crypto_sign_ed25519_ref10_fe_isnonzero
+#define fe_isnegative crypto_sign_ed25519_ref10_fe_isnegative
+#define fe_0 crypto_sign_ed25519_ref10_fe_0
+#define fe_1 crypto_sign_ed25519_ref10_fe_1
+#define fe_cswap crypto_sign_ed25519_ref10_fe_cswap
+#define fe_cmov crypto_sign_ed25519_ref10_fe_cmov
+#define fe_add crypto_sign_ed25519_ref10_fe_add
+#define fe_sub crypto_sign_ed25519_ref10_fe_sub
+#define fe_neg crypto_sign_ed25519_ref10_fe_neg
+#define fe_mul crypto_sign_ed25519_ref10_fe_mul
+#define fe_sq crypto_sign_ed25519_ref10_fe_sq
+#define fe_sq2 crypto_sign_ed25519_ref10_fe_sq2
+#define fe_mul121666 crypto_sign_ed25519_ref10_fe_mul121666
+#define fe_invert crypto_sign_ed25519_ref10_fe_invert
+#define fe_pow22523 crypto_sign_ed25519_ref10_fe_pow22523
+
+extern void fe_frombytes(fe,const unsigned char *);
+extern void fe_tobytes(unsigned char *,const fe);
+
+extern void fe_copy(fe,const fe);
+extern int fe_isnonzero(const fe);
+extern int fe_isnegative(const fe);
+extern void fe_0(fe);
+extern void fe_1(fe);
+extern void fe_cswap(fe,fe,unsigned int);
+extern void fe_cmov(fe,const fe,unsigned int);
+
+extern void fe_add(fe,const fe,const fe);
+extern void fe_sub(fe,const fe,const fe);
+extern void fe_neg(fe,const fe);
+extern void fe_mul(fe,const fe,const fe);
+extern void fe_sq(fe,const fe);
+extern void fe_sq2(fe,const fe);
+extern void fe_mul121666(fe,const fe);
+extern void fe_invert(fe,const fe);
+extern void fe_pow22523(fe,const fe);
+
+#endif
diff --git a/plugin/auth_ed25519/ref10/fe_0.c b/plugin/auth_ed25519/ref10/fe_0.c
new file mode 100644
index 00000000..ec879d73
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_0.c
@@ -0,0 +1,19 @@
+#include "fe.h"
+
+/*
+h = 0
+*/
+
+void fe_0(fe h)
+{
+ h[0] = 0;
+ h[1] = 0;
+ h[2] = 0;
+ h[3] = 0;
+ h[4] = 0;
+ h[5] = 0;
+ h[6] = 0;
+ h[7] = 0;
+ h[8] = 0;
+ h[9] = 0;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_1.c b/plugin/auth_ed25519/ref10/fe_1.c
new file mode 100644
index 00000000..8cf77848
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_1.c
@@ -0,0 +1,19 @@
+#include "fe.h"
+
+/*
+h = 1
+*/
+
+void fe_1(fe h)
+{
+ h[0] = 1;
+ h[1] = 0;
+ h[2] = 0;
+ h[3] = 0;
+ h[4] = 0;
+ h[5] = 0;
+ h[6] = 0;
+ h[7] = 0;
+ h[8] = 0;
+ h[9] = 0;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_add.c b/plugin/auth_ed25519/ref10/fe_add.c
new file mode 100644
index 00000000..e6a81da2
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_add.c
@@ -0,0 +1,57 @@
+#include "fe.h"
+
+/*
+h = f + g
+Can overlap h with f or g.
+
+Preconditions:
+ |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+ |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+ |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+void fe_add(fe h,const fe f,const fe g)
+{
+ crypto_int32 f0 = f[0];
+ crypto_int32 f1 = f[1];
+ crypto_int32 f2 = f[2];
+ crypto_int32 f3 = f[3];
+ crypto_int32 f4 = f[4];
+ crypto_int32 f5 = f[5];
+ crypto_int32 f6 = f[6];
+ crypto_int32 f7 = f[7];
+ crypto_int32 f8 = f[8];
+ crypto_int32 f9 = f[9];
+ crypto_int32 g0 = g[0];
+ crypto_int32 g1 = g[1];
+ crypto_int32 g2 = g[2];
+ crypto_int32 g3 = g[3];
+ crypto_int32 g4 = g[4];
+ crypto_int32 g5 = g[5];
+ crypto_int32 g6 = g[6];
+ crypto_int32 g7 = g[7];
+ crypto_int32 g8 = g[8];
+ crypto_int32 g9 = g[9];
+ crypto_int32 h0 = f0 + g0;
+ crypto_int32 h1 = f1 + g1;
+ crypto_int32 h2 = f2 + g2;
+ crypto_int32 h3 = f3 + g3;
+ crypto_int32 h4 = f4 + g4;
+ crypto_int32 h5 = f5 + g5;
+ crypto_int32 h6 = f6 + g6;
+ crypto_int32 h7 = f7 + g7;
+ crypto_int32 h8 = f8 + g8;
+ crypto_int32 h9 = f9 + g9;
+ h[0] = h0;
+ h[1] = h1;
+ h[2] = h2;
+ h[3] = h3;
+ h[4] = h4;
+ h[5] = h5;
+ h[6] = h6;
+ h[7] = h7;
+ h[8] = h8;
+ h[9] = h9;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_cmov.c b/plugin/auth_ed25519/ref10/fe_cmov.c
new file mode 100644
index 00000000..8ca584fb
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_cmov.c
@@ -0,0 +1,63 @@
+#include "fe.h"
+
+/*
+Replace (f,g) with (g,g) if b == 1;
+replace (f,g) with (f,g) if b == 0.
+
+Preconditions: b in {0,1}.
+*/
+
+void fe_cmov(fe f,const fe g,unsigned int b)
+{
+ crypto_int32 f0 = f[0];
+ crypto_int32 f1 = f[1];
+ crypto_int32 f2 = f[2];
+ crypto_int32 f3 = f[3];
+ crypto_int32 f4 = f[4];
+ crypto_int32 f5 = f[5];
+ crypto_int32 f6 = f[6];
+ crypto_int32 f7 = f[7];
+ crypto_int32 f8 = f[8];
+ crypto_int32 f9 = f[9];
+ crypto_int32 g0 = g[0];
+ crypto_int32 g1 = g[1];
+ crypto_int32 g2 = g[2];
+ crypto_int32 g3 = g[3];
+ crypto_int32 g4 = g[4];
+ crypto_int32 g5 = g[5];
+ crypto_int32 g6 = g[6];
+ crypto_int32 g7 = g[7];
+ crypto_int32 g8 = g[8];
+ crypto_int32 g9 = g[9];
+ crypto_int32 x0 = f0 ^ g0;
+ crypto_int32 x1 = f1 ^ g1;
+ crypto_int32 x2 = f2 ^ g2;
+ crypto_int32 x3 = f3 ^ g3;
+ crypto_int32 x4 = f4 ^ g4;
+ crypto_int32 x5 = f5 ^ g5;
+ crypto_int32 x6 = f6 ^ g6;
+ crypto_int32 x7 = f7 ^ g7;
+ crypto_int32 x8 = f8 ^ g8;
+ crypto_int32 x9 = f9 ^ g9;
+ b = -b;
+ x0 &= b;
+ x1 &= b;
+ x2 &= b;
+ x3 &= b;
+ x4 &= b;
+ x5 &= b;
+ x6 &= b;
+ x7 &= b;
+ x8 &= b;
+ x9 &= b;
+ f[0] = f0 ^ x0;
+ f[1] = f1 ^ x1;
+ f[2] = f2 ^ x2;
+ f[3] = f3 ^ x3;
+ f[4] = f4 ^ x4;
+ f[5] = f5 ^ x5;
+ f[6] = f6 ^ x6;
+ f[7] = f7 ^ x7;
+ f[8] = f8 ^ x8;
+ f[9] = f9 ^ x9;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_copy.c b/plugin/auth_ed25519/ref10/fe_copy.c
new file mode 100644
index 00000000..9c5bf865
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_copy.c
@@ -0,0 +1,29 @@
+#include "fe.h"
+
+/*
+h = f
+*/
+
+void fe_copy(fe h,const fe f)
+{
+ crypto_int32 f0 = f[0];
+ crypto_int32 f1 = f[1];
+ crypto_int32 f2 = f[2];
+ crypto_int32 f3 = f[3];
+ crypto_int32 f4 = f[4];
+ crypto_int32 f5 = f[5];
+ crypto_int32 f6 = f[6];
+ crypto_int32 f7 = f[7];
+ crypto_int32 f8 = f[8];
+ crypto_int32 f9 = f[9];
+ h[0] = f0;
+ h[1] = f1;
+ h[2] = f2;
+ h[3] = f3;
+ h[4] = f4;
+ h[5] = f5;
+ h[6] = f6;
+ h[7] = f7;
+ h[8] = f8;
+ h[9] = f9;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_frombytes.c b/plugin/auth_ed25519/ref10/fe_frombytes.c
new file mode 100644
index 00000000..5c179174
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_frombytes.c
@@ -0,0 +1,73 @@
+#include "fe.h"
+#include "crypto_int64.h"
+#include "crypto_uint64.h"
+
+static crypto_uint64 load_3(const unsigned char *in)
+{
+ crypto_uint64 result;
+ result = (crypto_uint64) in[0];
+ result |= ((crypto_uint64) in[1]) << 8;
+ result |= ((crypto_uint64) in[2]) << 16;
+ return result;
+}
+
+static crypto_uint64 load_4(const unsigned char *in)
+{
+ crypto_uint64 result;
+ result = (crypto_uint64) in[0];
+ result |= ((crypto_uint64) in[1]) << 8;
+ result |= ((crypto_uint64) in[2]) << 16;
+ result |= ((crypto_uint64) in[3]) << 24;
+ return result;
+}
+
+/*
+Ignores top bit of h.
+*/
+
+void fe_frombytes(fe h,const unsigned char *s)
+{
+ crypto_int64 h0 = load_4(s);
+ crypto_int64 h1 = load_3(s + 4) << 6;
+ crypto_int64 h2 = load_3(s + 7) << 5;
+ crypto_int64 h3 = load_3(s + 10) << 3;
+ crypto_int64 h4 = load_3(s + 13) << 2;
+ crypto_int64 h5 = load_4(s + 16);
+ crypto_int64 h6 = load_3(s + 20) << 7;
+ crypto_int64 h7 = load_3(s + 23) << 5;
+ crypto_int64 h8 = load_3(s + 26) << 4;
+ crypto_int64 h9 = (load_3(s + 29) & 8388607) << 2;
+ crypto_int64 carry0;
+ crypto_int64 carry1;
+ crypto_int64 carry2;
+ crypto_int64 carry3;
+ crypto_int64 carry4;
+ crypto_int64 carry5;
+ crypto_int64 carry6;
+ crypto_int64 carry7;
+ crypto_int64 carry8;
+ crypto_int64 carry9;
+
+ carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+ carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+ carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+ carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+ carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+ carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+ carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+ carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+ carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+ carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+ h[0] = h0;
+ h[1] = h1;
+ h[2] = h2;
+ h[3] = h3;
+ h[4] = h4;
+ h[5] = h5;
+ h[6] = h6;
+ h[7] = h7;
+ h[8] = h8;
+ h[9] = h9;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_invert.c b/plugin/auth_ed25519/ref10/fe_invert.c
new file mode 100644
index 00000000..bcfdb8ff
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_invert.c
@@ -0,0 +1,14 @@
+#include "fe.h"
+
+void fe_invert(fe out,const fe z)
+{
+ fe t0;
+ fe t1;
+ fe t2;
+ fe t3;
+ int i;
+
+#include "pow225521.h"
+
+ return;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_isnegative.c b/plugin/auth_ed25519/ref10/fe_isnegative.c
new file mode 100644
index 00000000..3b2c8b8d
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_isnegative.c
@@ -0,0 +1,16 @@
+#include "fe.h"
+
+/*
+return 1 if f is in {1,3,5,...,q-2}
+return 0 if f is in {0,2,4,...,q-1}
+
+Preconditions:
+ |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+int fe_isnegative(const fe f)
+{
+ unsigned char s[32];
+ fe_tobytes(s,f);
+ return s[0] & 1;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_isnonzero.c b/plugin/auth_ed25519/ref10/fe_isnonzero.c
new file mode 100644
index 00000000..47568001
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_isnonzero.c
@@ -0,0 +1,19 @@
+#include "fe.h"
+#include "crypto_verify_32.h"
+
+/*
+return 1 if f == 0
+return 0 if f != 0
+
+Preconditions:
+ |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+static const unsigned char zero[32];
+
+int fe_isnonzero(const fe f)
+{
+ unsigned char s[32];
+ fe_tobytes(s,f);
+ return crypto_verify_32(s,zero);
+}
diff --git a/plugin/auth_ed25519/ref10/fe_mul.c b/plugin/auth_ed25519/ref10/fe_mul.c
new file mode 100644
index 00000000..26ca8b36
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_mul.c
@@ -0,0 +1,253 @@
+#include "fe.h"
+#include "crypto_int64.h"
+
+/*
+h = f * g
+Can overlap h with f or g.
+
+Preconditions:
+ |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+ |g| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+ |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+Notes on implementation strategy:
+
+Using schoolbook multiplication.
+Karatsuba would save a little in some cost models.
+
+Most multiplications by 2 and 19 are 32-bit precomputations;
+cheaper than 64-bit postcomputations.
+
+There is one remaining multiplication by 19 in the carry chain;
+one *19 precomputation can be merged into this,
+but the resulting data flow is considerably less clean.
+
+There are 12 carries below.
+10 of them are 2-way parallelizable and vectorizable.
+Can get away with 11 carries, but then data flow is much deeper.
+
+With tighter constraints on inputs can squeeze carries into int32.
+*/
+
+void fe_mul(fe h,const fe f,const fe g)
+{
+ crypto_int32 f0 = f[0];
+ crypto_int32 f1 = f[1];
+ crypto_int32 f2 = f[2];
+ crypto_int32 f3 = f[3];
+ crypto_int32 f4 = f[4];
+ crypto_int32 f5 = f[5];
+ crypto_int32 f6 = f[6];
+ crypto_int32 f7 = f[7];
+ crypto_int32 f8 = f[8];
+ crypto_int32 f9 = f[9];
+ crypto_int32 g0 = g[0];
+ crypto_int32 g1 = g[1];
+ crypto_int32 g2 = g[2];
+ crypto_int32 g3 = g[3];
+ crypto_int32 g4 = g[4];
+ crypto_int32 g5 = g[5];
+ crypto_int32 g6 = g[6];
+ crypto_int32 g7 = g[7];
+ crypto_int32 g8 = g[8];
+ crypto_int32 g9 = g[9];
+ crypto_int32 g1_19 = 19 * g1; /* 1.959375*2^29 */
+ crypto_int32 g2_19 = 19 * g2; /* 1.959375*2^30; still ok */
+ crypto_int32 g3_19 = 19 * g3;
+ crypto_int32 g4_19 = 19 * g4;
+ crypto_int32 g5_19 = 19 * g5;
+ crypto_int32 g6_19 = 19 * g6;
+ crypto_int32 g7_19 = 19 * g7;
+ crypto_int32 g8_19 = 19 * g8;
+ crypto_int32 g9_19 = 19 * g9;
+ crypto_int32 f1_2 = 2 * f1;
+ crypto_int32 f3_2 = 2 * f3;
+ crypto_int32 f5_2 = 2 * f5;
+ crypto_int32 f7_2 = 2 * f7;
+ crypto_int32 f9_2 = 2 * f9;
+ crypto_int64 f0g0 = f0 * (crypto_int64) g0;
+ crypto_int64 f0g1 = f0 * (crypto_int64) g1;
+ crypto_int64 f0g2 = f0 * (crypto_int64) g2;
+ crypto_int64 f0g3 = f0 * (crypto_int64) g3;
+ crypto_int64 f0g4 = f0 * (crypto_int64) g4;
+ crypto_int64 f0g5 = f0 * (crypto_int64) g5;
+ crypto_int64 f0g6 = f0 * (crypto_int64) g6;
+ crypto_int64 f0g7 = f0 * (crypto_int64) g7;
+ crypto_int64 f0g8 = f0 * (crypto_int64) g8;
+ crypto_int64 f0g9 = f0 * (crypto_int64) g9;
+ crypto_int64 f1g0 = f1 * (crypto_int64) g0;
+ crypto_int64 f1g1_2 = f1_2 * (crypto_int64) g1;
+ crypto_int64 f1g2 = f1 * (crypto_int64) g2;
+ crypto_int64 f1g3_2 = f1_2 * (crypto_int64) g3;
+ crypto_int64 f1g4 = f1 * (crypto_int64) g4;
+ crypto_int64 f1g5_2 = f1_2 * (crypto_int64) g5;
+ crypto_int64 f1g6 = f1 * (crypto_int64) g6;
+ crypto_int64 f1g7_2 = f1_2 * (crypto_int64) g7;
+ crypto_int64 f1g8 = f1 * (crypto_int64) g8;
+ crypto_int64 f1g9_38 = f1_2 * (crypto_int64) g9_19;
+ crypto_int64 f2g0 = f2 * (crypto_int64) g0;
+ crypto_int64 f2g1 = f2 * (crypto_int64) g1;
+ crypto_int64 f2g2 = f2 * (crypto_int64) g2;
+ crypto_int64 f2g3 = f2 * (crypto_int64) g3;
+ crypto_int64 f2g4 = f2 * (crypto_int64) g4;
+ crypto_int64 f2g5 = f2 * (crypto_int64) g5;
+ crypto_int64 f2g6 = f2 * (crypto_int64) g6;
+ crypto_int64 f2g7 = f2 * (crypto_int64) g7;
+ crypto_int64 f2g8_19 = f2 * (crypto_int64) g8_19;
+ crypto_int64 f2g9_19 = f2 * (crypto_int64) g9_19;
+ crypto_int64 f3g0 = f3 * (crypto_int64) g0;
+ crypto_int64 f3g1_2 = f3_2 * (crypto_int64) g1;
+ crypto_int64 f3g2 = f3 * (crypto_int64) g2;
+ crypto_int64 f3g3_2 = f3_2 * (crypto_int64) g3;
+ crypto_int64 f3g4 = f3 * (crypto_int64) g4;
+ crypto_int64 f3g5_2 = f3_2 * (crypto_int64) g5;
+ crypto_int64 f3g6 = f3 * (crypto_int64) g6;
+ crypto_int64 f3g7_38 = f3_2 * (crypto_int64) g7_19;
+ crypto_int64 f3g8_19 = f3 * (crypto_int64) g8_19;
+ crypto_int64 f3g9_38 = f3_2 * (crypto_int64) g9_19;
+ crypto_int64 f4g0 = f4 * (crypto_int64) g0;
+ crypto_int64 f4g1 = f4 * (crypto_int64) g1;
+ crypto_int64 f4g2 = f4 * (crypto_int64) g2;
+ crypto_int64 f4g3 = f4 * (crypto_int64) g3;
+ crypto_int64 f4g4 = f4 * (crypto_int64) g4;
+ crypto_int64 f4g5 = f4 * (crypto_int64) g5;
+ crypto_int64 f4g6_19 = f4 * (crypto_int64) g6_19;
+ crypto_int64 f4g7_19 = f4 * (crypto_int64) g7_19;
+ crypto_int64 f4g8_19 = f4 * (crypto_int64) g8_19;
+ crypto_int64 f4g9_19 = f4 * (crypto_int64) g9_19;
+ crypto_int64 f5g0 = f5 * (crypto_int64) g0;
+ crypto_int64 f5g1_2 = f5_2 * (crypto_int64) g1;
+ crypto_int64 f5g2 = f5 * (crypto_int64) g2;
+ crypto_int64 f5g3_2 = f5_2 * (crypto_int64) g3;
+ crypto_int64 f5g4 = f5 * (crypto_int64) g4;
+ crypto_int64 f5g5_38 = f5_2 * (crypto_int64) g5_19;
+ crypto_int64 f5g6_19 = f5 * (crypto_int64) g6_19;
+ crypto_int64 f5g7_38 = f5_2 * (crypto_int64) g7_19;
+ crypto_int64 f5g8_19 = f5 * (crypto_int64) g8_19;
+ crypto_int64 f5g9_38 = f5_2 * (crypto_int64) g9_19;
+ crypto_int64 f6g0 = f6 * (crypto_int64) g0;
+ crypto_int64 f6g1 = f6 * (crypto_int64) g1;
+ crypto_int64 f6g2 = f6 * (crypto_int64) g2;
+ crypto_int64 f6g3 = f6 * (crypto_int64) g3;
+ crypto_int64 f6g4_19 = f6 * (crypto_int64) g4_19;
+ crypto_int64 f6g5_19 = f6 * (crypto_int64) g5_19;
+ crypto_int64 f6g6_19 = f6 * (crypto_int64) g6_19;
+ crypto_int64 f6g7_19 = f6 * (crypto_int64) g7_19;
+ crypto_int64 f6g8_19 = f6 * (crypto_int64) g8_19;
+ crypto_int64 f6g9_19 = f6 * (crypto_int64) g9_19;
+ crypto_int64 f7g0 = f7 * (crypto_int64) g0;
+ crypto_int64 f7g1_2 = f7_2 * (crypto_int64) g1;
+ crypto_int64 f7g2 = f7 * (crypto_int64) g2;
+ crypto_int64 f7g3_38 = f7_2 * (crypto_int64) g3_19;
+ crypto_int64 f7g4_19 = f7 * (crypto_int64) g4_19;
+ crypto_int64 f7g5_38 = f7_2 * (crypto_int64) g5_19;
+ crypto_int64 f7g6_19 = f7 * (crypto_int64) g6_19;
+ crypto_int64 f7g7_38 = f7_2 * (crypto_int64) g7_19;
+ crypto_int64 f7g8_19 = f7 * (crypto_int64) g8_19;
+ crypto_int64 f7g9_38 = f7_2 * (crypto_int64) g9_19;
+ crypto_int64 f8g0 = f8 * (crypto_int64) g0;
+ crypto_int64 f8g1 = f8 * (crypto_int64) g1;
+ crypto_int64 f8g2_19 = f8 * (crypto_int64) g2_19;
+ crypto_int64 f8g3_19 = f8 * (crypto_int64) g3_19;
+ crypto_int64 f8g4_19 = f8 * (crypto_int64) g4_19;
+ crypto_int64 f8g5_19 = f8 * (crypto_int64) g5_19;
+ crypto_int64 f8g6_19 = f8 * (crypto_int64) g6_19;
+ crypto_int64 f8g7_19 = f8 * (crypto_int64) g7_19;
+ crypto_int64 f8g8_19 = f8 * (crypto_int64) g8_19;
+ crypto_int64 f8g9_19 = f8 * (crypto_int64) g9_19;
+ crypto_int64 f9g0 = f9 * (crypto_int64) g0;
+ crypto_int64 f9g1_38 = f9_2 * (crypto_int64) g1_19;
+ crypto_int64 f9g2_19 = f9 * (crypto_int64) g2_19;
+ crypto_int64 f9g3_38 = f9_2 * (crypto_int64) g3_19;
+ crypto_int64 f9g4_19 = f9 * (crypto_int64) g4_19;
+ crypto_int64 f9g5_38 = f9_2 * (crypto_int64) g5_19;
+ crypto_int64 f9g6_19 = f9 * (crypto_int64) g6_19;
+ crypto_int64 f9g7_38 = f9_2 * (crypto_int64) g7_19;
+ crypto_int64 f9g8_19 = f9 * (crypto_int64) g8_19;
+ crypto_int64 f9g9_38 = f9_2 * (crypto_int64) g9_19;
+ crypto_int64 h0 = f0g0+f1g9_38+f2g8_19+f3g7_38+f4g6_19+f5g5_38+f6g4_19+f7g3_38+f8g2_19+f9g1_38;
+ crypto_int64 h1 = f0g1+f1g0 +f2g9_19+f3g8_19+f4g7_19+f5g6_19+f6g5_19+f7g4_19+f8g3_19+f9g2_19;
+ crypto_int64 h2 = f0g2+f1g1_2 +f2g0 +f3g9_38+f4g8_19+f5g7_38+f6g6_19+f7g5_38+f8g4_19+f9g3_38;
+ crypto_int64 h3 = f0g3+f1g2 +f2g1 +f3g0 +f4g9_19+f5g8_19+f6g7_19+f7g6_19+f8g5_19+f9g4_19;
+ crypto_int64 h4 = f0g4+f1g3_2 +f2g2 +f3g1_2 +f4g0 +f5g9_38+f6g8_19+f7g7_38+f8g6_19+f9g5_38;
+ crypto_int64 h5 = f0g5+f1g4 +f2g3 +f3g2 +f4g1 +f5g0 +f6g9_19+f7g8_19+f8g7_19+f9g6_19;
+ crypto_int64 h6 = f0g6+f1g5_2 +f2g4 +f3g3_2 +f4g2 +f5g1_2 +f6g0 +f7g9_38+f8g8_19+f9g7_38;
+ crypto_int64 h7 = f0g7+f1g6 +f2g5 +f3g4 +f4g3 +f5g2 +f6g1 +f7g0 +f8g9_19+f9g8_19;
+ crypto_int64 h8 = f0g8+f1g7_2 +f2g6 +f3g5_2 +f4g4 +f5g3_2 +f6g2 +f7g1_2 +f8g0 +f9g9_38;
+ crypto_int64 h9 = f0g9+f1g8 +f2g7 +f3g6 +f4g5 +f5g4 +f6g3 +f7g2 +f8g1 +f9g0 ;
+ crypto_int64 carry0;
+ crypto_int64 carry1;
+ crypto_int64 carry2;
+ crypto_int64 carry3;
+ crypto_int64 carry4;
+ crypto_int64 carry5;
+ crypto_int64 carry6;
+ crypto_int64 carry7;
+ crypto_int64 carry8;
+ crypto_int64 carry9;
+
+ /*
+ |h0| <= (1.65*1.65*2^52*(1+19+19+19+19)+1.65*1.65*2^50*(38+38+38+38+38))
+ i.e. |h0| <= 1.4*2^60; narrower ranges for h2, h4, h6, h8
+ |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19))
+ i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9
+ */
+
+ carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+ carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+ /* |h0| <= 2^25 */
+ /* |h4| <= 2^25 */
+ /* |h1| <= 1.71*2^59 */
+ /* |h5| <= 1.71*2^59 */
+
+ carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+ carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+ /* |h1| <= 2^24; from now on fits into int32 */
+ /* |h5| <= 2^24; from now on fits into int32 */
+ /* |h2| <= 1.41*2^60 */
+ /* |h6| <= 1.41*2^60 */
+
+ carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+ carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+ /* |h2| <= 2^25; from now on fits into int32 unchanged */
+ /* |h6| <= 2^25; from now on fits into int32 unchanged */
+ /* |h3| <= 1.71*2^59 */
+ /* |h7| <= 1.71*2^59 */
+
+ carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+ carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+ /* |h3| <= 2^24; from now on fits into int32 unchanged */
+ /* |h7| <= 2^24; from now on fits into int32 unchanged */
+ /* |h4| <= 1.72*2^34 */
+ /* |h8| <= 1.41*2^60 */
+
+ carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+ carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+ /* |h4| <= 2^25; from now on fits into int32 unchanged */
+ /* |h8| <= 2^25; from now on fits into int32 unchanged */
+ /* |h5| <= 1.01*2^24 */
+ /* |h9| <= 1.71*2^59 */
+
+ carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+ /* |h9| <= 2^24; from now on fits into int32 unchanged */
+ /* |h0| <= 1.1*2^39 */
+
+ carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+ /* |h0| <= 2^25; from now on fits into int32 unchanged */
+ /* |h1| <= 1.01*2^24 */
+
+ h[0] = h0;
+ h[1] = h1;
+ h[2] = h2;
+ h[3] = h3;
+ h[4] = h4;
+ h[5] = h5;
+ h[6] = h6;
+ h[7] = h7;
+ h[8] = h8;
+ h[9] = h9;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_neg.c b/plugin/auth_ed25519/ref10/fe_neg.c
new file mode 100644
index 00000000..2078ce52
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_neg.c
@@ -0,0 +1,45 @@
+#include "fe.h"
+
+/*
+h = -f
+
+Preconditions:
+ |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+ |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+*/
+
+void fe_neg(fe h,const fe f)
+{
+ crypto_int32 f0 = f[0];
+ crypto_int32 f1 = f[1];
+ crypto_int32 f2 = f[2];
+ crypto_int32 f3 = f[3];
+ crypto_int32 f4 = f[4];
+ crypto_int32 f5 = f[5];
+ crypto_int32 f6 = f[6];
+ crypto_int32 f7 = f[7];
+ crypto_int32 f8 = f[8];
+ crypto_int32 f9 = f[9];
+ crypto_int32 h0 = -f0;
+ crypto_int32 h1 = -f1;
+ crypto_int32 h2 = -f2;
+ crypto_int32 h3 = -f3;
+ crypto_int32 h4 = -f4;
+ crypto_int32 h5 = -f5;
+ crypto_int32 h6 = -f6;
+ crypto_int32 h7 = -f7;
+ crypto_int32 h8 = -f8;
+ crypto_int32 h9 = -f9;
+ h[0] = h0;
+ h[1] = h1;
+ h[2] = h2;
+ h[3] = h3;
+ h[4] = h4;
+ h[5] = h5;
+ h[6] = h6;
+ h[7] = h7;
+ h[8] = h8;
+ h[9] = h9;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_pow22523.c b/plugin/auth_ed25519/ref10/fe_pow22523.c
new file mode 100644
index 00000000..56675a59
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_pow22523.c
@@ -0,0 +1,13 @@
+#include "fe.h"
+
+void fe_pow22523(fe out,const fe z)
+{
+ fe t0;
+ fe t1;
+ fe t2;
+ int i;
+
+#include "pow22523.h"
+
+ return;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_sq.c b/plugin/auth_ed25519/ref10/fe_sq.c
new file mode 100644
index 00000000..8dd11984
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_sq.c
@@ -0,0 +1,149 @@
+#include "fe.h"
+#include "crypto_int64.h"
+
+/*
+h = f * f
+Can overlap h with f.
+
+Preconditions:
+ |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+ |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+See fe_mul.c for discussion of implementation strategy.
+*/
+
+void fe_sq(fe h,const fe f)
+{
+ crypto_int32 f0 = f[0];
+ crypto_int32 f1 = f[1];
+ crypto_int32 f2 = f[2];
+ crypto_int32 f3 = f[3];
+ crypto_int32 f4 = f[4];
+ crypto_int32 f5 = f[5];
+ crypto_int32 f6 = f[6];
+ crypto_int32 f7 = f[7];
+ crypto_int32 f8 = f[8];
+ crypto_int32 f9 = f[9];
+ crypto_int32 f0_2 = 2 * f0;
+ crypto_int32 f1_2 = 2 * f1;
+ crypto_int32 f2_2 = 2 * f2;
+ crypto_int32 f3_2 = 2 * f3;
+ crypto_int32 f4_2 = 2 * f4;
+ crypto_int32 f5_2 = 2 * f5;
+ crypto_int32 f6_2 = 2 * f6;
+ crypto_int32 f7_2 = 2 * f7;
+ crypto_int32 f5_38 = 38 * f5; /* 1.959375*2^30 */
+ crypto_int32 f6_19 = 19 * f6; /* 1.959375*2^30 */
+ crypto_int32 f7_38 = 38 * f7; /* 1.959375*2^30 */
+ crypto_int32 f8_19 = 19 * f8; /* 1.959375*2^30 */
+ crypto_int32 f9_38 = 38 * f9; /* 1.959375*2^30 */
+ crypto_int64 f0f0 = f0 * (crypto_int64) f0;
+ crypto_int64 f0f1_2 = f0_2 * (crypto_int64) f1;
+ crypto_int64 f0f2_2 = f0_2 * (crypto_int64) f2;
+ crypto_int64 f0f3_2 = f0_2 * (crypto_int64) f3;
+ crypto_int64 f0f4_2 = f0_2 * (crypto_int64) f4;
+ crypto_int64 f0f5_2 = f0_2 * (crypto_int64) f5;
+ crypto_int64 f0f6_2 = f0_2 * (crypto_int64) f6;
+ crypto_int64 f0f7_2 = f0_2 * (crypto_int64) f7;
+ crypto_int64 f0f8_2 = f0_2 * (crypto_int64) f8;
+ crypto_int64 f0f9_2 = f0_2 * (crypto_int64) f9;
+ crypto_int64 f1f1_2 = f1_2 * (crypto_int64) f1;
+ crypto_int64 f1f2_2 = f1_2 * (crypto_int64) f2;
+ crypto_int64 f1f3_4 = f1_2 * (crypto_int64) f3_2;
+ crypto_int64 f1f4_2 = f1_2 * (crypto_int64) f4;
+ crypto_int64 f1f5_4 = f1_2 * (crypto_int64) f5_2;
+ crypto_int64 f1f6_2 = f1_2 * (crypto_int64) f6;
+ crypto_int64 f1f7_4 = f1_2 * (crypto_int64) f7_2;
+ crypto_int64 f1f8_2 = f1_2 * (crypto_int64) f8;
+ crypto_int64 f1f9_76 = f1_2 * (crypto_int64) f9_38;
+ crypto_int64 f2f2 = f2 * (crypto_int64) f2;
+ crypto_int64 f2f3_2 = f2_2 * (crypto_int64) f3;
+ crypto_int64 f2f4_2 = f2_2 * (crypto_int64) f4;
+ crypto_int64 f2f5_2 = f2_2 * (crypto_int64) f5;
+ crypto_int64 f2f6_2 = f2_2 * (crypto_int64) f6;
+ crypto_int64 f2f7_2 = f2_2 * (crypto_int64) f7;
+ crypto_int64 f2f8_38 = f2_2 * (crypto_int64) f8_19;
+ crypto_int64 f2f9_38 = f2 * (crypto_int64) f9_38;
+ crypto_int64 f3f3_2 = f3_2 * (crypto_int64) f3;
+ crypto_int64 f3f4_2 = f3_2 * (crypto_int64) f4;
+ crypto_int64 f3f5_4 = f3_2 * (crypto_int64) f5_2;
+ crypto_int64 f3f6_2 = f3_2 * (crypto_int64) f6;
+ crypto_int64 f3f7_76 = f3_2 * (crypto_int64) f7_38;
+ crypto_int64 f3f8_38 = f3_2 * (crypto_int64) f8_19;
+ crypto_int64 f3f9_76 = f3_2 * (crypto_int64) f9_38;
+ crypto_int64 f4f4 = f4 * (crypto_int64) f4;
+ crypto_int64 f4f5_2 = f4_2 * (crypto_int64) f5;
+ crypto_int64 f4f6_38 = f4_2 * (crypto_int64) f6_19;
+ crypto_int64 f4f7_38 = f4 * (crypto_int64) f7_38;
+ crypto_int64 f4f8_38 = f4_2 * (crypto_int64) f8_19;
+ crypto_int64 f4f9_38 = f4 * (crypto_int64) f9_38;
+ crypto_int64 f5f5_38 = f5 * (crypto_int64) f5_38;
+ crypto_int64 f5f6_38 = f5_2 * (crypto_int64) f6_19;
+ crypto_int64 f5f7_76 = f5_2 * (crypto_int64) f7_38;
+ crypto_int64 f5f8_38 = f5_2 * (crypto_int64) f8_19;
+ crypto_int64 f5f9_76 = f5_2 * (crypto_int64) f9_38;
+ crypto_int64 f6f6_19 = f6 * (crypto_int64) f6_19;
+ crypto_int64 f6f7_38 = f6 * (crypto_int64) f7_38;
+ crypto_int64 f6f8_38 = f6_2 * (crypto_int64) f8_19;
+ crypto_int64 f6f9_38 = f6 * (crypto_int64) f9_38;
+ crypto_int64 f7f7_38 = f7 * (crypto_int64) f7_38;
+ crypto_int64 f7f8_38 = f7_2 * (crypto_int64) f8_19;
+ crypto_int64 f7f9_76 = f7_2 * (crypto_int64) f9_38;
+ crypto_int64 f8f8_19 = f8 * (crypto_int64) f8_19;
+ crypto_int64 f8f9_38 = f8 * (crypto_int64) f9_38;
+ crypto_int64 f9f9_38 = f9 * (crypto_int64) f9_38;
+ crypto_int64 h0 = f0f0 +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38;
+ crypto_int64 h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38;
+ crypto_int64 h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19;
+ crypto_int64 h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38;
+ crypto_int64 h4 = f0f4_2+f1f3_4 +f2f2 +f5f9_76+f6f8_38+f7f7_38;
+ crypto_int64 h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38;
+ crypto_int64 h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19;
+ crypto_int64 h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38;
+ crypto_int64 h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4 +f9f9_38;
+ crypto_int64 h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2;
+ crypto_int64 carry0;
+ crypto_int64 carry1;
+ crypto_int64 carry2;
+ crypto_int64 carry3;
+ crypto_int64 carry4;
+ crypto_int64 carry5;
+ crypto_int64 carry6;
+ crypto_int64 carry7;
+ crypto_int64 carry8;
+ crypto_int64 carry9;
+
+ carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+ carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+
+ carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+ carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+
+ carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+ carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+
+ carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+ carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+ carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+ carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+ carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+
+ carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+
+ h[0] = h0;
+ h[1] = h1;
+ h[2] = h2;
+ h[3] = h3;
+ h[4] = h4;
+ h[5] = h5;
+ h[6] = h6;
+ h[7] = h7;
+ h[8] = h8;
+ h[9] = h9;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_sq2.c b/plugin/auth_ed25519/ref10/fe_sq2.c
new file mode 100644
index 00000000..026ed3aa
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_sq2.c
@@ -0,0 +1,160 @@
+#include "fe.h"
+#include "crypto_int64.h"
+
+/*
+h = 2 * f * f
+Can overlap h with f.
+
+Preconditions:
+ |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+
+Postconditions:
+ |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+*/
+
+/*
+See fe_mul.c for discussion of implementation strategy.
+*/
+
+void fe_sq2(fe h,const fe f)
+{
+ crypto_int32 f0 = f[0];
+ crypto_int32 f1 = f[1];
+ crypto_int32 f2 = f[2];
+ crypto_int32 f3 = f[3];
+ crypto_int32 f4 = f[4];
+ crypto_int32 f5 = f[5];
+ crypto_int32 f6 = f[6];
+ crypto_int32 f7 = f[7];
+ crypto_int32 f8 = f[8];
+ crypto_int32 f9 = f[9];
+ crypto_int32 f0_2 = 2 * f0;
+ crypto_int32 f1_2 = 2 * f1;
+ crypto_int32 f2_2 = 2 * f2;
+ crypto_int32 f3_2 = 2 * f3;
+ crypto_int32 f4_2 = 2 * f4;
+ crypto_int32 f5_2 = 2 * f5;
+ crypto_int32 f6_2 = 2 * f6;
+ crypto_int32 f7_2 = 2 * f7;
+ crypto_int32 f5_38 = 38 * f5; /* 1.959375*2^30 */
+ crypto_int32 f6_19 = 19 * f6; /* 1.959375*2^30 */
+ crypto_int32 f7_38 = 38 * f7; /* 1.959375*2^30 */
+ crypto_int32 f8_19 = 19 * f8; /* 1.959375*2^30 */
+ crypto_int32 f9_38 = 38 * f9; /* 1.959375*2^30 */
+ crypto_int64 f0f0 = f0 * (crypto_int64) f0;
+ crypto_int64 f0f1_2 = f0_2 * (crypto_int64) f1;
+ crypto_int64 f0f2_2 = f0_2 * (crypto_int64) f2;
+ crypto_int64 f0f3_2 = f0_2 * (crypto_int64) f3;
+ crypto_int64 f0f4_2 = f0_2 * (crypto_int64) f4;
+ crypto_int64 f0f5_2 = f0_2 * (crypto_int64) f5;
+ crypto_int64 f0f6_2 = f0_2 * (crypto_int64) f6;
+ crypto_int64 f0f7_2 = f0_2 * (crypto_int64) f7;
+ crypto_int64 f0f8_2 = f0_2 * (crypto_int64) f8;
+ crypto_int64 f0f9_2 = f0_2 * (crypto_int64) f9;
+ crypto_int64 f1f1_2 = f1_2 * (crypto_int64) f1;
+ crypto_int64 f1f2_2 = f1_2 * (crypto_int64) f2;
+ crypto_int64 f1f3_4 = f1_2 * (crypto_int64) f3_2;
+ crypto_int64 f1f4_2 = f1_2 * (crypto_int64) f4;
+ crypto_int64 f1f5_4 = f1_2 * (crypto_int64) f5_2;
+ crypto_int64 f1f6_2 = f1_2 * (crypto_int64) f6;
+ crypto_int64 f1f7_4 = f1_2 * (crypto_int64) f7_2;
+ crypto_int64 f1f8_2 = f1_2 * (crypto_int64) f8;
+ crypto_int64 f1f9_76 = f1_2 * (crypto_int64) f9_38;
+ crypto_int64 f2f2 = f2 * (crypto_int64) f2;
+ crypto_int64 f2f3_2 = f2_2 * (crypto_int64) f3;
+ crypto_int64 f2f4_2 = f2_2 * (crypto_int64) f4;
+ crypto_int64 f2f5_2 = f2_2 * (crypto_int64) f5;
+ crypto_int64 f2f6_2 = f2_2 * (crypto_int64) f6;
+ crypto_int64 f2f7_2 = f2_2 * (crypto_int64) f7;
+ crypto_int64 f2f8_38 = f2_2 * (crypto_int64) f8_19;
+ crypto_int64 f2f9_38 = f2 * (crypto_int64) f9_38;
+ crypto_int64 f3f3_2 = f3_2 * (crypto_int64) f3;
+ crypto_int64 f3f4_2 = f3_2 * (crypto_int64) f4;
+ crypto_int64 f3f5_4 = f3_2 * (crypto_int64) f5_2;
+ crypto_int64 f3f6_2 = f3_2 * (crypto_int64) f6;
+ crypto_int64 f3f7_76 = f3_2 * (crypto_int64) f7_38;
+ crypto_int64 f3f8_38 = f3_2 * (crypto_int64) f8_19;
+ crypto_int64 f3f9_76 = f3_2 * (crypto_int64) f9_38;
+ crypto_int64 f4f4 = f4 * (crypto_int64) f4;
+ crypto_int64 f4f5_2 = f4_2 * (crypto_int64) f5;
+ crypto_int64 f4f6_38 = f4_2 * (crypto_int64) f6_19;
+ crypto_int64 f4f7_38 = f4 * (crypto_int64) f7_38;
+ crypto_int64 f4f8_38 = f4_2 * (crypto_int64) f8_19;
+ crypto_int64 f4f9_38 = f4 * (crypto_int64) f9_38;
+ crypto_int64 f5f5_38 = f5 * (crypto_int64) f5_38;
+ crypto_int64 f5f6_38 = f5_2 * (crypto_int64) f6_19;
+ crypto_int64 f5f7_76 = f5_2 * (crypto_int64) f7_38;
+ crypto_int64 f5f8_38 = f5_2 * (crypto_int64) f8_19;
+ crypto_int64 f5f9_76 = f5_2 * (crypto_int64) f9_38;
+ crypto_int64 f6f6_19 = f6 * (crypto_int64) f6_19;
+ crypto_int64 f6f7_38 = f6 * (crypto_int64) f7_38;
+ crypto_int64 f6f8_38 = f6_2 * (crypto_int64) f8_19;
+ crypto_int64 f6f9_38 = f6 * (crypto_int64) f9_38;
+ crypto_int64 f7f7_38 = f7 * (crypto_int64) f7_38;
+ crypto_int64 f7f8_38 = f7_2 * (crypto_int64) f8_19;
+ crypto_int64 f7f9_76 = f7_2 * (crypto_int64) f9_38;
+ crypto_int64 f8f8_19 = f8 * (crypto_int64) f8_19;
+ crypto_int64 f8f9_38 = f8 * (crypto_int64) f9_38;
+ crypto_int64 f9f9_38 = f9 * (crypto_int64) f9_38;
+ crypto_int64 h0 = f0f0 +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38;
+ crypto_int64 h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38;
+ crypto_int64 h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19;
+ crypto_int64 h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38;
+ crypto_int64 h4 = f0f4_2+f1f3_4 +f2f2 +f5f9_76+f6f8_38+f7f7_38;
+ crypto_int64 h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38;
+ crypto_int64 h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19;
+ crypto_int64 h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38;
+ crypto_int64 h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4 +f9f9_38;
+ crypto_int64 h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2;
+ crypto_int64 carry0;
+ crypto_int64 carry1;
+ crypto_int64 carry2;
+ crypto_int64 carry3;
+ crypto_int64 carry4;
+ crypto_int64 carry5;
+ crypto_int64 carry6;
+ crypto_int64 carry7;
+ crypto_int64 carry8;
+ crypto_int64 carry9;
+
+ h0 += h0;
+ h1 += h1;
+ h2 += h2;
+ h3 += h3;
+ h4 += h4;
+ h5 += h5;
+ h6 += h6;
+ h7 += h7;
+ h8 += h8;
+ h9 += h9;
+
+ carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+ carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+
+ carry1 = (h1 + (crypto_int64) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+ carry5 = (h5 + (crypto_int64) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+
+ carry2 = (h2 + (crypto_int64) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+ carry6 = (h6 + (crypto_int64) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+
+ carry3 = (h3 + (crypto_int64) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+ carry7 = (h7 + (crypto_int64) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+ carry4 = (h4 + (crypto_int64) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+ carry8 = (h8 + (crypto_int64) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+ carry9 = (h9 + (crypto_int64) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+
+ carry0 = (h0 + (crypto_int64) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+
+ h[0] = h0;
+ h[1] = h1;
+ h[2] = h2;
+ h[3] = h3;
+ h[4] = h4;
+ h[5] = h5;
+ h[6] = h6;
+ h[7] = h7;
+ h[8] = h8;
+ h[9] = h9;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_sub.c b/plugin/auth_ed25519/ref10/fe_sub.c
new file mode 100644
index 00000000..6e26b7df
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_sub.c
@@ -0,0 +1,57 @@
+#include "fe.h"
+
+/*
+h = f - g
+Can overlap h with f or g.
+
+Preconditions:
+ |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+ |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+ |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+void fe_sub(fe h,const fe f,const fe g)
+{
+ crypto_int32 f0 = f[0];
+ crypto_int32 f1 = f[1];
+ crypto_int32 f2 = f[2];
+ crypto_int32 f3 = f[3];
+ crypto_int32 f4 = f[4];
+ crypto_int32 f5 = f[5];
+ crypto_int32 f6 = f[6];
+ crypto_int32 f7 = f[7];
+ crypto_int32 f8 = f[8];
+ crypto_int32 f9 = f[9];
+ crypto_int32 g0 = g[0];
+ crypto_int32 g1 = g[1];
+ crypto_int32 g2 = g[2];
+ crypto_int32 g3 = g[3];
+ crypto_int32 g4 = g[4];
+ crypto_int32 g5 = g[5];
+ crypto_int32 g6 = g[6];
+ crypto_int32 g7 = g[7];
+ crypto_int32 g8 = g[8];
+ crypto_int32 g9 = g[9];
+ crypto_int32 h0 = f0 - g0;
+ crypto_int32 h1 = f1 - g1;
+ crypto_int32 h2 = f2 - g2;
+ crypto_int32 h3 = f3 - g3;
+ crypto_int32 h4 = f4 - g4;
+ crypto_int32 h5 = f5 - g5;
+ crypto_int32 h6 = f6 - g6;
+ crypto_int32 h7 = f7 - g7;
+ crypto_int32 h8 = f8 - g8;
+ crypto_int32 h9 = f9 - g9;
+ h[0] = h0;
+ h[1] = h1;
+ h[2] = h2;
+ h[3] = h3;
+ h[4] = h4;
+ h[5] = h5;
+ h[6] = h6;
+ h[7] = h7;
+ h[8] = h8;
+ h[9] = h9;
+}
diff --git a/plugin/auth_ed25519/ref10/fe_tobytes.c b/plugin/auth_ed25519/ref10/fe_tobytes.c
new file mode 100644
index 00000000..0a63baf9
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/fe_tobytes.c
@@ -0,0 +1,119 @@
+#include "fe.h"
+
+/*
+Preconditions:
+ |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+
+Write p=2^255-19; q=floor(h/p).
+Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
+
+Proof:
+ Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
+ Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4.
+
+ Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
+ Then 0<y<1.
+
+ Write r=h-pq.
+ Have 0<=r<=p-1=2^255-20.
+ Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
+
+ Write x=r+19(2^-255)r+y.
+ Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
+
+ Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
+ so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
+*/
+
+void fe_tobytes(unsigned char *s,const fe h)
+{
+ crypto_int32 h0 = h[0];
+ crypto_int32 h1 = h[1];
+ crypto_int32 h2 = h[2];
+ crypto_int32 h3 = h[3];
+ crypto_int32 h4 = h[4];
+ crypto_int32 h5 = h[5];
+ crypto_int32 h6 = h[6];
+ crypto_int32 h7 = h[7];
+ crypto_int32 h8 = h[8];
+ crypto_int32 h9 = h[9];
+ crypto_int32 q;
+ crypto_int32 carry0;
+ crypto_int32 carry1;
+ crypto_int32 carry2;
+ crypto_int32 carry3;
+ crypto_int32 carry4;
+ crypto_int32 carry5;
+ crypto_int32 carry6;
+ crypto_int32 carry7;
+ crypto_int32 carry8;
+ crypto_int32 carry9;
+
+ q = (19 * h9 + (((crypto_int32) 1) << 24)) >> 25;
+ q = (h0 + q) >> 26;
+ q = (h1 + q) >> 25;
+ q = (h2 + q) >> 26;
+ q = (h3 + q) >> 25;
+ q = (h4 + q) >> 26;
+ q = (h5 + q) >> 25;
+ q = (h6 + q) >> 26;
+ q = (h7 + q) >> 25;
+ q = (h8 + q) >> 26;
+ q = (h9 + q) >> 25;
+
+ /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */
+ h0 += 19 * q;
+ /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */
+
+ carry0 = h0 >> 26; h1 += carry0; h0 -= carry0 << 26;
+ carry1 = h1 >> 25; h2 += carry1; h1 -= carry1 << 25;
+ carry2 = h2 >> 26; h3 += carry2; h2 -= carry2 << 26;
+ carry3 = h3 >> 25; h4 += carry3; h3 -= carry3 << 25;
+ carry4 = h4 >> 26; h5 += carry4; h4 -= carry4 << 26;
+ carry5 = h5 >> 25; h6 += carry5; h5 -= carry5 << 25;
+ carry6 = h6 >> 26; h7 += carry6; h6 -= carry6 << 26;
+ carry7 = h7 >> 25; h8 += carry7; h7 -= carry7 << 25;
+ carry8 = h8 >> 26; h9 += carry8; h8 -= carry8 << 26;
+ carry9 = h9 >> 25; h9 -= carry9 << 25;
+ /* h10 = carry9 */
+
+ /*
+ Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
+ Have h0+...+2^230 h9 between 0 and 2^255-1;
+ evidently 2^255 h10-2^255 q = 0.
+ Goal: Output h0+...+2^230 h9.
+ */
+
+ s[0] = h0 >> 0;
+ s[1] = h0 >> 8;
+ s[2] = h0 >> 16;
+ s[3] = (h0 >> 24) | (h1 << 2);
+ s[4] = h1 >> 6;
+ s[5] = h1 >> 14;
+ s[6] = (h1 >> 22) | (h2 << 3);
+ s[7] = h2 >> 5;
+ s[8] = h2 >> 13;
+ s[9] = (h2 >> 21) | (h3 << 5);
+ s[10] = h3 >> 3;
+ s[11] = h3 >> 11;
+ s[12] = (h3 >> 19) | (h4 << 6);
+ s[13] = h4 >> 2;
+ s[14] = h4 >> 10;
+ s[15] = h4 >> 18;
+ s[16] = h5 >> 0;
+ s[17] = h5 >> 8;
+ s[18] = h5 >> 16;
+ s[19] = (h5 >> 24) | (h6 << 1);
+ s[20] = h6 >> 7;
+ s[21] = h6 >> 15;
+ s[22] = (h6 >> 23) | (h7 << 3);
+ s[23] = h7 >> 5;
+ s[24] = h7 >> 13;
+ s[25] = (h7 >> 21) | (h8 << 4);
+ s[26] = h8 >> 4;
+ s[27] = h8 >> 12;
+ s[28] = (h8 >> 20) | (h9 << 6);
+ s[29] = h9 >> 2;
+ s[30] = h9 >> 10;
+ s[31] = h9 >> 18;
+}
diff --git a/plugin/auth_ed25519/ref10/ge.h b/plugin/auth_ed25519/ref10/ge.h
new file mode 100644
index 00000000..55e95f95
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge.h
@@ -0,0 +1,95 @@
+#ifndef GE_H
+#define GE_H
+
+/*
+ge means group element.
+
+Here the group is the set of pairs (x,y) of field elements (see fe.h)
+satisfying -x^2 + y^2 = 1 + d x^2y^2
+where d = -121665/121666.
+
+Representations:
+ ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
+ ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
+ ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
+ ge_precomp (Duif): (y+x,y-x,2dxy)
+*/
+
+#include "fe.h"
+
+typedef struct {
+ fe X;
+ fe Y;
+ fe Z;
+} ge_p2;
+
+typedef struct {
+ fe X;
+ fe Y;
+ fe Z;
+ fe T;
+} ge_p3;
+
+typedef struct {
+ fe X;
+ fe Y;
+ fe Z;
+ fe T;
+} ge_p1p1;
+
+typedef struct {
+ fe yplusx;
+ fe yminusx;
+ fe xy2d;
+} ge_precomp;
+
+typedef struct {
+ fe YplusX;
+ fe YminusX;
+ fe Z;
+ fe T2d;
+} ge_cached;
+
+#define ge_frombytes_negate_vartime crypto_sign_ed25519_ref10_ge_frombytes_negate_vartime
+#define ge_tobytes crypto_sign_ed25519_ref10_ge_tobytes
+#define ge_p3_tobytes crypto_sign_ed25519_ref10_ge_p3_tobytes
+
+#define ge_p2_0 crypto_sign_ed25519_ref10_ge_p2_0
+#define ge_p3_0 crypto_sign_ed25519_ref10_ge_p3_0
+#define ge_precomp_0 crypto_sign_ed25519_ref10_ge_precomp_0
+#define ge_p3_to_p2 crypto_sign_ed25519_ref10_ge_p3_to_p2
+#define ge_p3_to_cached crypto_sign_ed25519_ref10_ge_p3_to_cached
+#define ge_p1p1_to_p2 crypto_sign_ed25519_ref10_ge_p1p1_to_p2
+#define ge_p1p1_to_p3 crypto_sign_ed25519_ref10_ge_p1p1_to_p3
+#define ge_p2_dbl crypto_sign_ed25519_ref10_ge_p2_dbl
+#define ge_p3_dbl crypto_sign_ed25519_ref10_ge_p3_dbl
+
+#define ge_madd crypto_sign_ed25519_ref10_ge_madd
+#define ge_msub crypto_sign_ed25519_ref10_ge_msub
+#define ge_add crypto_sign_ed25519_ref10_ge_add
+#define ge_sub crypto_sign_ed25519_ref10_ge_sub
+#define ge_scalarmult_base crypto_sign_ed25519_ref10_ge_scalarmult_base
+#define ge_double_scalarmult_vartime crypto_sign_ed25519_ref10_ge_double_scalarmult_vartime
+
+extern void ge_tobytes(unsigned char *,const ge_p2 *);
+extern void ge_p3_tobytes(unsigned char *,const ge_p3 *);
+extern int ge_frombytes_negate_vartime(ge_p3 *,const unsigned char *);
+
+extern void ge_p2_0(ge_p2 *);
+extern void ge_p3_0(ge_p3 *);
+extern void ge_precomp_0(ge_precomp *);
+extern void ge_p3_to_p2(ge_p2 *,const ge_p3 *);
+extern void ge_p3_to_cached(ge_cached *,const ge_p3 *);
+extern void ge_p1p1_to_p2(ge_p2 *,const ge_p1p1 *);
+extern void ge_p1p1_to_p3(ge_p3 *,const ge_p1p1 *);
+extern void ge_p2_dbl(ge_p1p1 *,const ge_p2 *);
+extern void ge_p3_dbl(ge_p1p1 *,const ge_p3 *);
+
+extern void ge_madd(ge_p1p1 *,const ge_p3 *,const ge_precomp *);
+extern void ge_msub(ge_p1p1 *,const ge_p3 *,const ge_precomp *);
+extern void ge_add(ge_p1p1 *,const ge_p3 *,const ge_cached *);
+extern void ge_sub(ge_p1p1 *,const ge_p3 *,const ge_cached *);
+extern void ge_scalarmult_base(ge_p3 *,const unsigned char *);
+extern void ge_double_scalarmult_vartime(ge_p2 *,const unsigned char *,const ge_p3 *,const unsigned char *);
+
+#endif
diff --git a/plugin/auth_ed25519/ref10/ge_add.c b/plugin/auth_ed25519/ref10/ge_add.c
new file mode 100644
index 00000000..da7ff5d2
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_add.c
@@ -0,0 +1,11 @@
+#include "ge.h"
+
+/*
+r = p + q
+*/
+
+void ge_add(ge_p1p1 *r,const ge_p3 *p,const ge_cached *q)
+{
+ fe t0;
+#include "ge_add.h"
+}
diff --git a/plugin/auth_ed25519/ref10/ge_add.h b/plugin/auth_ed25519/ref10/ge_add.h
new file mode 100644
index 00000000..7481f8ff
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_add.h
@@ -0,0 +1,97 @@
+
+/* qhasm: enter ge_add */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe Z2 */
+
+/* qhasm: fe T1 */
+
+/* qhasm: fe ZZ */
+
+/* qhasm: fe YpX2 */
+
+/* qhasm: fe YmX2 */
+
+/* qhasm: fe T2d2 */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: fe YpX1 */
+
+/* qhasm: fe YmX1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe B */
+
+/* qhasm: fe C */
+
+/* qhasm: fe D */
+
+/* qhasm: YpX1 = Y1+X1 */
+/* asm 1: fe_add(>YpX1=fe#1,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_add(>YpX1=r->X,<Y1=p->Y,<X1=p->X); */
+fe_add(r->X,p->Y,p->X);
+
+/* qhasm: YmX1 = Y1-X1 */
+/* asm 1: fe_sub(>YmX1=fe#2,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_sub(>YmX1=r->Y,<Y1=p->Y,<X1=p->X); */
+fe_sub(r->Y,p->Y,p->X);
+
+/* qhasm: A = YpX1*YpX2 */
+/* asm 1: fe_mul(>A=fe#3,<YpX1=fe#1,<YpX2=fe#15); */
+/* asm 2: fe_mul(>A=r->Z,<YpX1=r->X,<YpX2=q->YplusX); */
+fe_mul(r->Z,r->X,q->YplusX);
+
+/* qhasm: B = YmX1*YmX2 */
+/* asm 1: fe_mul(>B=fe#2,<YmX1=fe#2,<YmX2=fe#16); */
+/* asm 2: fe_mul(>B=r->Y,<YmX1=r->Y,<YmX2=q->YminusX); */
+fe_mul(r->Y,r->Y,q->YminusX);
+
+/* qhasm: C = T2d2*T1 */
+/* asm 1: fe_mul(>C=fe#4,<T2d2=fe#18,<T1=fe#14); */
+/* asm 2: fe_mul(>C=r->T,<T2d2=q->T2d,<T1=p->T); */
+fe_mul(r->T,q->T2d,p->T);
+
+/* qhasm: ZZ = Z1*Z2 */
+/* asm 1: fe_mul(>ZZ=fe#1,<Z1=fe#13,<Z2=fe#17); */
+/* asm 2: fe_mul(>ZZ=r->X,<Z1=p->Z,<Z2=q->Z); */
+fe_mul(r->X,p->Z,q->Z);
+
+/* qhasm: D = 2*ZZ */
+/* asm 1: fe_add(>D=fe#5,<ZZ=fe#1,<ZZ=fe#1); */
+/* asm 2: fe_add(>D=t0,<ZZ=r->X,<ZZ=r->X); */
+fe_add(t0,r->X,r->X);
+
+/* qhasm: X3 = A-B */
+/* asm 1: fe_sub(>X3=fe#1,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_sub(>X3=r->X,<A=r->Z,<B=r->Y); */
+fe_sub(r->X,r->Z,r->Y);
+
+/* qhasm: Y3 = A+B */
+/* asm 1: fe_add(>Y3=fe#2,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_add(>Y3=r->Y,<A=r->Z,<B=r->Y); */
+fe_add(r->Y,r->Z,r->Y);
+
+/* qhasm: Z3 = D+C */
+/* asm 1: fe_add(>Z3=fe#3,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_add(>Z3=r->Z,<D=t0,<C=r->T); */
+fe_add(r->Z,t0,r->T);
+
+/* qhasm: T3 = D-C */
+/* asm 1: fe_sub(>T3=fe#4,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_sub(>T3=r->T,<D=t0,<C=r->T); */
+fe_sub(r->T,t0,r->T);
+
+/* qhasm: return */
diff --git a/plugin/auth_ed25519/ref10/ge_double_scalarmult.c b/plugin/auth_ed25519/ref10/ge_double_scalarmult.c
new file mode 100644
index 00000000..f8bf4bf7
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_double_scalarmult.c
@@ -0,0 +1,96 @@
+#include "ge.h"
+
+static void slide(signed char *r,const unsigned char *a)
+{
+ int i;
+ int b;
+ int k;
+
+ for (i = 0;i < 256;++i)
+ r[i] = 1 & (a[i >> 3] >> (i & 7));
+
+ for (i = 0;i < 256;++i)
+ if (r[i]) {
+ for (b = 1;b <= 6 && i + b < 256;++b) {
+ if (r[i + b]) {
+ if (r[i] + (r[i + b] << b) <= 15) {
+ r[i] += r[i + b] << b; r[i + b] = 0;
+ } else if (r[i] - (r[i + b] << b) >= -15) {
+ r[i] -= r[i + b] << b;
+ for (k = i + b;k < 256;++k) {
+ if (!r[k]) {
+ r[k] = 1;
+ break;
+ }
+ r[k] = 0;
+ }
+ } else
+ break;
+ }
+ }
+ }
+
+}
+
+static ge_precomp Bi[8] = {
+#include "base2.h"
+} ;
+
+/*
+r = a * A + b * B
+where a = a[0]+256*a[1]+...+256^31 a[31].
+and b = b[0]+256*b[1]+...+256^31 b[31].
+B is the Ed25519 base point (x,4/5) with x positive.
+*/
+
+void ge_double_scalarmult_vartime(ge_p2 *r,const unsigned char *a,const ge_p3 *A,const unsigned char *b)
+{
+ signed char aslide[256];
+ signed char bslide[256];
+ ge_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */
+ ge_p1p1 t;
+ ge_p3 u;
+ ge_p3 A2;
+ int i;
+
+ slide(aslide,a);
+ slide(bslide,b);
+
+ ge_p3_to_cached(&Ai[0],A);
+ ge_p3_dbl(&t,A); ge_p1p1_to_p3(&A2,&t);
+ ge_add(&t,&A2,&Ai[0]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[1],&u);
+ ge_add(&t,&A2,&Ai[1]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[2],&u);
+ ge_add(&t,&A2,&Ai[2]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[3],&u);
+ ge_add(&t,&A2,&Ai[3]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[4],&u);
+ ge_add(&t,&A2,&Ai[4]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[5],&u);
+ ge_add(&t,&A2,&Ai[5]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[6],&u);
+ ge_add(&t,&A2,&Ai[6]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[7],&u);
+
+ ge_p2_0(r);
+
+ for (i = 255;i >= 0;--i) {
+ if (aslide[i] || bslide[i]) break;
+ }
+
+ for (;i >= 0;--i) {
+ ge_p2_dbl(&t,r);
+
+ if (aslide[i] > 0) {
+ ge_p1p1_to_p3(&u,&t);
+ ge_add(&t,&u,&Ai[aslide[i]/2]);
+ } else if (aslide[i] < 0) {
+ ge_p1p1_to_p3(&u,&t);
+ ge_sub(&t,&u,&Ai[(-aslide[i])/2]);
+ }
+
+ if (bslide[i] > 0) {
+ ge_p1p1_to_p3(&u,&t);
+ ge_madd(&t,&u,&Bi[bslide[i]/2]);
+ } else if (bslide[i] < 0) {
+ ge_p1p1_to_p3(&u,&t);
+ ge_msub(&t,&u,&Bi[(-bslide[i])/2]);
+ }
+
+ ge_p1p1_to_p2(r,&t);
+ }
+}
diff --git a/plugin/auth_ed25519/ref10/ge_frombytes.c b/plugin/auth_ed25519/ref10/ge_frombytes.c
new file mode 100644
index 00000000..1a059ee9
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_frombytes.c
@@ -0,0 +1,50 @@
+#include "ge.h"
+
+static const fe d = {
+#include "d.h"
+} ;
+
+static const fe sqrtm1 = {
+#include "sqrtm1.h"
+} ;
+
+int ge_frombytes_negate_vartime(ge_p3 *h,const unsigned char *s)
+{
+ fe u;
+ fe v;
+ fe v3;
+ fe vxx;
+ fe check;
+
+ fe_frombytes(h->Y,s);
+ fe_1(h->Z);
+ fe_sq(u,h->Y);
+ fe_mul(v,u,d);
+ fe_sub(u,u,h->Z); /* u = y^2-1 */
+ fe_add(v,v,h->Z); /* v = dy^2+1 */
+
+ fe_sq(v3,v);
+ fe_mul(v3,v3,v); /* v3 = v^3 */
+ fe_sq(h->X,v3);
+ fe_mul(h->X,h->X,v);
+ fe_mul(h->X,h->X,u); /* x = uv^7 */
+
+ fe_pow22523(h->X,h->X); /* x = (uv^7)^((q-5)/8) */
+ fe_mul(h->X,h->X,v3);
+ fe_mul(h->X,h->X,u); /* x = uv^3(uv^7)^((q-5)/8) */
+
+ fe_sq(vxx,h->X);
+ fe_mul(vxx,vxx,v);
+ fe_sub(check,vxx,u); /* vx^2-u */
+ if (fe_isnonzero(check)) {
+ fe_add(check,vxx,u); /* vx^2+u */
+ if (fe_isnonzero(check)) return -1;
+ fe_mul(h->X,h->X,sqrtm1);
+ }
+
+ if (fe_isnegative(h->X) == (s[31] >> 7))
+ fe_neg(h->X,h->X);
+
+ fe_mul(h->T,h->X,h->Y);
+ return 0;
+}
diff --git a/plugin/auth_ed25519/ref10/ge_madd.c b/plugin/auth_ed25519/ref10/ge_madd.c
new file mode 100644
index 00000000..62257177
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_madd.c
@@ -0,0 +1,11 @@
+#include "ge.h"
+
+/*
+r = p + q
+*/
+
+void ge_madd(ge_p1p1 *r,const ge_p3 *p,const ge_precomp *q)
+{
+ fe t0;
+#include "ge_madd.h"
+}
diff --git a/plugin/auth_ed25519/ref10/ge_madd.h b/plugin/auth_ed25519/ref10/ge_madd.h
new file mode 100644
index 00000000..ecae8495
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_madd.h
@@ -0,0 +1,88 @@
+
+/* qhasm: enter ge_madd */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe T1 */
+
+/* qhasm: fe ypx2 */
+
+/* qhasm: fe ymx2 */
+
+/* qhasm: fe xy2d2 */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: fe YpX1 */
+
+/* qhasm: fe YmX1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe B */
+
+/* qhasm: fe C */
+
+/* qhasm: fe D */
+
+/* qhasm: YpX1 = Y1+X1 */
+/* asm 1: fe_add(>YpX1=fe#1,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_add(>YpX1=r->X,<Y1=p->Y,<X1=p->X); */
+fe_add(r->X,p->Y,p->X);
+
+/* qhasm: YmX1 = Y1-X1 */
+/* asm 1: fe_sub(>YmX1=fe#2,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_sub(>YmX1=r->Y,<Y1=p->Y,<X1=p->X); */
+fe_sub(r->Y,p->Y,p->X);
+
+/* qhasm: A = YpX1*ypx2 */
+/* asm 1: fe_mul(>A=fe#3,<YpX1=fe#1,<ypx2=fe#15); */
+/* asm 2: fe_mul(>A=r->Z,<YpX1=r->X,<ypx2=q->yplusx); */
+fe_mul(r->Z,r->X,q->yplusx);
+
+/* qhasm: B = YmX1*ymx2 */
+/* asm 1: fe_mul(>B=fe#2,<YmX1=fe#2,<ymx2=fe#16); */
+/* asm 2: fe_mul(>B=r->Y,<YmX1=r->Y,<ymx2=q->yminusx); */
+fe_mul(r->Y,r->Y,q->yminusx);
+
+/* qhasm: C = xy2d2*T1 */
+/* asm 1: fe_mul(>C=fe#4,<xy2d2=fe#17,<T1=fe#14); */
+/* asm 2: fe_mul(>C=r->T,<xy2d2=q->xy2d,<T1=p->T); */
+fe_mul(r->T,q->xy2d,p->T);
+
+/* qhasm: D = 2*Z1 */
+/* asm 1: fe_add(>D=fe#5,<Z1=fe#13,<Z1=fe#13); */
+/* asm 2: fe_add(>D=t0,<Z1=p->Z,<Z1=p->Z); */
+fe_add(t0,p->Z,p->Z);
+
+/* qhasm: X3 = A-B */
+/* asm 1: fe_sub(>X3=fe#1,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_sub(>X3=r->X,<A=r->Z,<B=r->Y); */
+fe_sub(r->X,r->Z,r->Y);
+
+/* qhasm: Y3 = A+B */
+/* asm 1: fe_add(>Y3=fe#2,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_add(>Y3=r->Y,<A=r->Z,<B=r->Y); */
+fe_add(r->Y,r->Z,r->Y);
+
+/* qhasm: Z3 = D+C */
+/* asm 1: fe_add(>Z3=fe#3,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_add(>Z3=r->Z,<D=t0,<C=r->T); */
+fe_add(r->Z,t0,r->T);
+
+/* qhasm: T3 = D-C */
+/* asm 1: fe_sub(>T3=fe#4,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_sub(>T3=r->T,<D=t0,<C=r->T); */
+fe_sub(r->T,t0,r->T);
+
+/* qhasm: return */
diff --git a/plugin/auth_ed25519/ref10/ge_msub.c b/plugin/auth_ed25519/ref10/ge_msub.c
new file mode 100644
index 00000000..741ecbf1
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_msub.c
@@ -0,0 +1,11 @@
+#include "ge.h"
+
+/*
+r = p - q
+*/
+
+void ge_msub(ge_p1p1 *r,const ge_p3 *p,const ge_precomp *q)
+{
+ fe t0;
+#include "ge_msub.h"
+}
diff --git a/plugin/auth_ed25519/ref10/ge_msub.h b/plugin/auth_ed25519/ref10/ge_msub.h
new file mode 100644
index 00000000..500f986b
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_msub.h
@@ -0,0 +1,88 @@
+
+/* qhasm: enter ge_msub */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe T1 */
+
+/* qhasm: fe ypx2 */
+
+/* qhasm: fe ymx2 */
+
+/* qhasm: fe xy2d2 */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: fe YpX1 */
+
+/* qhasm: fe YmX1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe B */
+
+/* qhasm: fe C */
+
+/* qhasm: fe D */
+
+/* qhasm: YpX1 = Y1+X1 */
+/* asm 1: fe_add(>YpX1=fe#1,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_add(>YpX1=r->X,<Y1=p->Y,<X1=p->X); */
+fe_add(r->X,p->Y,p->X);
+
+/* qhasm: YmX1 = Y1-X1 */
+/* asm 1: fe_sub(>YmX1=fe#2,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_sub(>YmX1=r->Y,<Y1=p->Y,<X1=p->X); */
+fe_sub(r->Y,p->Y,p->X);
+
+/* qhasm: A = YpX1*ymx2 */
+/* asm 1: fe_mul(>A=fe#3,<YpX1=fe#1,<ymx2=fe#16); */
+/* asm 2: fe_mul(>A=r->Z,<YpX1=r->X,<ymx2=q->yminusx); */
+fe_mul(r->Z,r->X,q->yminusx);
+
+/* qhasm: B = YmX1*ypx2 */
+/* asm 1: fe_mul(>B=fe#2,<YmX1=fe#2,<ypx2=fe#15); */
+/* asm 2: fe_mul(>B=r->Y,<YmX1=r->Y,<ypx2=q->yplusx); */
+fe_mul(r->Y,r->Y,q->yplusx);
+
+/* qhasm: C = xy2d2*T1 */
+/* asm 1: fe_mul(>C=fe#4,<xy2d2=fe#17,<T1=fe#14); */
+/* asm 2: fe_mul(>C=r->T,<xy2d2=q->xy2d,<T1=p->T); */
+fe_mul(r->T,q->xy2d,p->T);
+
+/* qhasm: D = 2*Z1 */
+/* asm 1: fe_add(>D=fe#5,<Z1=fe#13,<Z1=fe#13); */
+/* asm 2: fe_add(>D=t0,<Z1=p->Z,<Z1=p->Z); */
+fe_add(t0,p->Z,p->Z);
+
+/* qhasm: X3 = A-B */
+/* asm 1: fe_sub(>X3=fe#1,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_sub(>X3=r->X,<A=r->Z,<B=r->Y); */
+fe_sub(r->X,r->Z,r->Y);
+
+/* qhasm: Y3 = A+B */
+/* asm 1: fe_add(>Y3=fe#2,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_add(>Y3=r->Y,<A=r->Z,<B=r->Y); */
+fe_add(r->Y,r->Z,r->Y);
+
+/* qhasm: Z3 = D-C */
+/* asm 1: fe_sub(>Z3=fe#3,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_sub(>Z3=r->Z,<D=t0,<C=r->T); */
+fe_sub(r->Z,t0,r->T);
+
+/* qhasm: T3 = D+C */
+/* asm 1: fe_add(>T3=fe#4,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_add(>T3=r->T,<D=t0,<C=r->T); */
+fe_add(r->T,t0,r->T);
+
+/* qhasm: return */
diff --git a/plugin/auth_ed25519/ref10/ge_p1p1_to_p2.c b/plugin/auth_ed25519/ref10/ge_p1p1_to_p2.c
new file mode 100644
index 00000000..9bb5013d
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_p1p1_to_p2.c
@@ -0,0 +1,12 @@
+#include "ge.h"
+
+/*
+r = p
+*/
+
+extern void ge_p1p1_to_p2(ge_p2 *r,const ge_p1p1 *p)
+{
+ fe_mul(r->X,p->X,p->T);
+ fe_mul(r->Y,p->Y,p->Z);
+ fe_mul(r->Z,p->Z,p->T);
+}
diff --git a/plugin/auth_ed25519/ref10/ge_p1p1_to_p3.c b/plugin/auth_ed25519/ref10/ge_p1p1_to_p3.c
new file mode 100644
index 00000000..2f57b109
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_p1p1_to_p3.c
@@ -0,0 +1,13 @@
+#include "ge.h"
+
+/*
+r = p
+*/
+
+extern void ge_p1p1_to_p3(ge_p3 *r,const ge_p1p1 *p)
+{
+ fe_mul(r->X,p->X,p->T);
+ fe_mul(r->Y,p->Y,p->Z);
+ fe_mul(r->Z,p->Z,p->T);
+ fe_mul(r->T,p->X,p->Y);
+}
diff --git a/plugin/auth_ed25519/ref10/ge_p2_0.c b/plugin/auth_ed25519/ref10/ge_p2_0.c
new file mode 100644
index 00000000..6191d1e6
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_p2_0.c
@@ -0,0 +1,8 @@
+#include "ge.h"
+
+void ge_p2_0(ge_p2 *h)
+{
+ fe_0(h->X);
+ fe_1(h->Y);
+ fe_1(h->Z);
+}
diff --git a/plugin/auth_ed25519/ref10/ge_p2_dbl.c b/plugin/auth_ed25519/ref10/ge_p2_dbl.c
new file mode 100644
index 00000000..2e332b5c
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_p2_dbl.c
@@ -0,0 +1,11 @@
+#include "ge.h"
+
+/*
+r = 2 * p
+*/
+
+void ge_p2_dbl(ge_p1p1 *r,const ge_p2 *p)
+{
+ fe t0;
+#include "ge_p2_dbl.h"
+}
diff --git a/plugin/auth_ed25519/ref10/ge_p2_dbl.h b/plugin/auth_ed25519/ref10/ge_p2_dbl.h
new file mode 100644
index 00000000..128efed9
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_p2_dbl.h
@@ -0,0 +1,73 @@
+
+/* qhasm: enter ge_p2_dbl */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe AA */
+
+/* qhasm: fe XX */
+
+/* qhasm: fe YY */
+
+/* qhasm: fe B */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: XX=X1^2 */
+/* asm 1: fe_sq(>XX=fe#1,<X1=fe#11); */
+/* asm 2: fe_sq(>XX=r->X,<X1=p->X); */
+fe_sq(r->X,p->X);
+
+/* qhasm: YY=Y1^2 */
+/* asm 1: fe_sq(>YY=fe#3,<Y1=fe#12); */
+/* asm 2: fe_sq(>YY=r->Z,<Y1=p->Y); */
+fe_sq(r->Z,p->Y);
+
+/* qhasm: B=2*Z1^2 */
+/* asm 1: fe_sq2(>B=fe#4,<Z1=fe#13); */
+/* asm 2: fe_sq2(>B=r->T,<Z1=p->Z); */
+fe_sq2(r->T,p->Z);
+
+/* qhasm: A=X1+Y1 */
+/* asm 1: fe_add(>A=fe#2,<X1=fe#11,<Y1=fe#12); */
+/* asm 2: fe_add(>A=r->Y,<X1=p->X,<Y1=p->Y); */
+fe_add(r->Y,p->X,p->Y);
+
+/* qhasm: AA=A^2 */
+/* asm 1: fe_sq(>AA=fe#5,<A=fe#2); */
+/* asm 2: fe_sq(>AA=t0,<A=r->Y); */
+fe_sq(t0,r->Y);
+
+/* qhasm: Y3=YY+XX */
+/* asm 1: fe_add(>Y3=fe#2,<YY=fe#3,<XX=fe#1); */
+/* asm 2: fe_add(>Y3=r->Y,<YY=r->Z,<XX=r->X); */
+fe_add(r->Y,r->Z,r->X);
+
+/* qhasm: Z3=YY-XX */
+/* asm 1: fe_sub(>Z3=fe#3,<YY=fe#3,<XX=fe#1); */
+/* asm 2: fe_sub(>Z3=r->Z,<YY=r->Z,<XX=r->X); */
+fe_sub(r->Z,r->Z,r->X);
+
+/* qhasm: X3=AA-Y3 */
+/* asm 1: fe_sub(>X3=fe#1,<AA=fe#5,<Y3=fe#2); */
+/* asm 2: fe_sub(>X3=r->X,<AA=t0,<Y3=r->Y); */
+fe_sub(r->X,t0,r->Y);
+
+/* qhasm: T3=B-Z3 */
+/* asm 1: fe_sub(>T3=fe#4,<B=fe#4,<Z3=fe#3); */
+/* asm 2: fe_sub(>T3=r->T,<B=r->T,<Z3=r->Z); */
+fe_sub(r->T,r->T,r->Z);
+
+/* qhasm: return */
diff --git a/plugin/auth_ed25519/ref10/ge_p3_0.c b/plugin/auth_ed25519/ref10/ge_p3_0.c
new file mode 100644
index 00000000..401b2935
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_p3_0.c
@@ -0,0 +1,9 @@
+#include "ge.h"
+
+void ge_p3_0(ge_p3 *h)
+{
+ fe_0(h->X);
+ fe_1(h->Y);
+ fe_1(h->Z);
+ fe_0(h->T);
+}
diff --git a/plugin/auth_ed25519/ref10/ge_p3_dbl.c b/plugin/auth_ed25519/ref10/ge_p3_dbl.c
new file mode 100644
index 00000000..0d8a0591
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_p3_dbl.c
@@ -0,0 +1,12 @@
+#include "ge.h"
+
+/*
+r = 2 * p
+*/
+
+void ge_p3_dbl(ge_p1p1 *r,const ge_p3 *p)
+{
+ ge_p2 q;
+ ge_p3_to_p2(&q,p);
+ ge_p2_dbl(r,&q);
+}
diff --git a/plugin/auth_ed25519/ref10/ge_p3_to_cached.c b/plugin/auth_ed25519/ref10/ge_p3_to_cached.c
new file mode 100644
index 00000000..bde64228
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_p3_to_cached.c
@@ -0,0 +1,17 @@
+#include "ge.h"
+
+/*
+r = p
+*/
+
+static const fe d2 = {
+#include "d2.h"
+} ;
+
+extern void ge_p3_to_cached(ge_cached *r,const ge_p3 *p)
+{
+ fe_add(r->YplusX,p->Y,p->X);
+ fe_sub(r->YminusX,p->Y,p->X);
+ fe_copy(r->Z,p->Z);
+ fe_mul(r->T2d,p->T,d2);
+}
diff --git a/plugin/auth_ed25519/ref10/ge_p3_to_p2.c b/plugin/auth_ed25519/ref10/ge_p3_to_p2.c
new file mode 100644
index 00000000..e532a9e4
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_p3_to_p2.c
@@ -0,0 +1,12 @@
+#include "ge.h"
+
+/*
+r = p
+*/
+
+extern void ge_p3_to_p2(ge_p2 *r,const ge_p3 *p)
+{
+ fe_copy(r->X,p->X);
+ fe_copy(r->Y,p->Y);
+ fe_copy(r->Z,p->Z);
+}
diff --git a/plugin/auth_ed25519/ref10/ge_p3_tobytes.c b/plugin/auth_ed25519/ref10/ge_p3_tobytes.c
new file mode 100644
index 00000000..21cb2fc6
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_p3_tobytes.c
@@ -0,0 +1,14 @@
+#include "ge.h"
+
+void ge_p3_tobytes(unsigned char *s,const ge_p3 *h)
+{
+ fe recip;
+ fe x;
+ fe y;
+
+ fe_invert(recip,h->Z);
+ fe_mul(x,h->X,recip);
+ fe_mul(y,h->Y,recip);
+ fe_tobytes(s,y);
+ s[31] ^= fe_isnegative(x) << 7;
+}
diff --git a/plugin/auth_ed25519/ref10/ge_precomp_0.c b/plugin/auth_ed25519/ref10/ge_precomp_0.c
new file mode 100644
index 00000000..2e218861
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_precomp_0.c
@@ -0,0 +1,8 @@
+#include "ge.h"
+
+void ge_precomp_0(ge_precomp *h)
+{
+ fe_1(h->yplusx);
+ fe_1(h->yminusx);
+ fe_0(h->xy2d);
+}
diff --git a/plugin/auth_ed25519/ref10/ge_scalarmult_base.c b/plugin/auth_ed25519/ref10/ge_scalarmult_base.c
new file mode 100644
index 00000000..421e4fa0
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_scalarmult_base.c
@@ -0,0 +1,105 @@
+#include "ge.h"
+#include "crypto_uint32.h"
+
+static unsigned char equal(signed char b,signed char c)
+{
+ unsigned char ub = b;
+ unsigned char uc = c;
+ unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */
+ crypto_uint32 y = x; /* 0: yes; 1..255: no */
+ y -= 1; /* 4294967295: yes; 0..254: no */
+ y >>= 31; /* 1: yes; 0: no */
+ return y;
+}
+
+static unsigned char negative(signed char b)
+{
+ unsigned long long x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */
+ x >>= 63; /* 1: yes; 0: no */
+ return x;
+}
+
+static void cmov(ge_precomp *t,ge_precomp *u,unsigned char b)
+{
+ fe_cmov(t->yplusx,u->yplusx,b);
+ fe_cmov(t->yminusx,u->yminusx,b);
+ fe_cmov(t->xy2d,u->xy2d,b);
+}
+
+/* base[i][j] = (j+1)*256^i*B */
+static ge_precomp base[32][8] = {
+#include "base.h"
+} ;
+
+static void select(ge_precomp *t,int pos,signed char b)
+{
+ ge_precomp minust;
+ unsigned char bnegative = negative(b);
+ unsigned char babs = b - (((-bnegative) & b) << 1);
+
+ ge_precomp_0(t);
+ cmov(t,&base[pos][0],equal(babs,1));
+ cmov(t,&base[pos][1],equal(babs,2));
+ cmov(t,&base[pos][2],equal(babs,3));
+ cmov(t,&base[pos][3],equal(babs,4));
+ cmov(t,&base[pos][4],equal(babs,5));
+ cmov(t,&base[pos][5],equal(babs,6));
+ cmov(t,&base[pos][6],equal(babs,7));
+ cmov(t,&base[pos][7],equal(babs,8));
+ fe_copy(minust.yplusx,t->yminusx);
+ fe_copy(minust.yminusx,t->yplusx);
+ fe_neg(minust.xy2d,t->xy2d);
+ cmov(t,&minust,bnegative);
+}
+
+/*
+h = a * B
+where a = a[0]+256*a[1]+...+256^31 a[31]
+B is the Ed25519 base point (x,4/5) with x positive.
+
+Preconditions:
+ a[31] <= 127
+*/
+
+void ge_scalarmult_base(ge_p3 *h,const unsigned char *a)
+{
+ signed char e[64];
+ signed char carry;
+ ge_p1p1 r;
+ ge_p2 s;
+ ge_precomp t;
+ int i;
+
+ for (i = 0;i < 32;++i) {
+ e[2 * i + 0] = (a[i] >> 0) & 15;
+ e[2 * i + 1] = (a[i] >> 4) & 15;
+ }
+ /* each e[i] is between 0 and 15 */
+ /* e[63] is between 0 and 7 */
+
+ carry = 0;
+ for (i = 0;i < 63;++i) {
+ e[i] += carry;
+ carry = e[i] + 8;
+ carry >>= 4;
+ e[i] -= carry << 4;
+ }
+ e[63] += carry;
+ /* each e[i] is between -8 and 8 */
+
+ ge_p3_0(h);
+ for (i = 1;i < 64;i += 2) {
+ select(&t,i / 2,e[i]);
+ ge_madd(&r,h,&t); ge_p1p1_to_p3(h,&r);
+ }
+
+ ge_p3_dbl(&r,h); ge_p1p1_to_p2(&s,&r);
+ ge_p2_dbl(&r,&s); ge_p1p1_to_p2(&s,&r);
+ ge_p2_dbl(&r,&s); ge_p1p1_to_p2(&s,&r);
+ ge_p2_dbl(&r,&s); ge_p1p1_to_p3(h,&r);
+
+ for (i = 0;i < 64;i += 2) {
+ select(&t,i / 2,e[i]);
+ ge_madd(&r,h,&t); ge_p1p1_to_p3(h,&r);
+ }
+}
diff --git a/plugin/auth_ed25519/ref10/ge_sub.c b/plugin/auth_ed25519/ref10/ge_sub.c
new file mode 100644
index 00000000..69f3d540
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_sub.c
@@ -0,0 +1,11 @@
+#include "ge.h"
+
+/*
+r = p - q
+*/
+
+void ge_sub(ge_p1p1 *r,const ge_p3 *p,const ge_cached *q)
+{
+ fe t0;
+#include "ge_sub.h"
+}
diff --git a/plugin/auth_ed25519/ref10/ge_sub.h b/plugin/auth_ed25519/ref10/ge_sub.h
new file mode 100644
index 00000000..b4ef1f5d
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_sub.h
@@ -0,0 +1,97 @@
+
+/* qhasm: enter ge_sub */
+
+/* qhasm: fe X1 */
+
+/* qhasm: fe Y1 */
+
+/* qhasm: fe Z1 */
+
+/* qhasm: fe Z2 */
+
+/* qhasm: fe T1 */
+
+/* qhasm: fe ZZ */
+
+/* qhasm: fe YpX2 */
+
+/* qhasm: fe YmX2 */
+
+/* qhasm: fe T2d2 */
+
+/* qhasm: fe X3 */
+
+/* qhasm: fe Y3 */
+
+/* qhasm: fe Z3 */
+
+/* qhasm: fe T3 */
+
+/* qhasm: fe YpX1 */
+
+/* qhasm: fe YmX1 */
+
+/* qhasm: fe A */
+
+/* qhasm: fe B */
+
+/* qhasm: fe C */
+
+/* qhasm: fe D */
+
+/* qhasm: YpX1 = Y1+X1 */
+/* asm 1: fe_add(>YpX1=fe#1,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_add(>YpX1=r->X,<Y1=p->Y,<X1=p->X); */
+fe_add(r->X,p->Y,p->X);
+
+/* qhasm: YmX1 = Y1-X1 */
+/* asm 1: fe_sub(>YmX1=fe#2,<Y1=fe#12,<X1=fe#11); */
+/* asm 2: fe_sub(>YmX1=r->Y,<Y1=p->Y,<X1=p->X); */
+fe_sub(r->Y,p->Y,p->X);
+
+/* qhasm: A = YpX1*YmX2 */
+/* asm 1: fe_mul(>A=fe#3,<YpX1=fe#1,<YmX2=fe#16); */
+/* asm 2: fe_mul(>A=r->Z,<YpX1=r->X,<YmX2=q->YminusX); */
+fe_mul(r->Z,r->X,q->YminusX);
+
+/* qhasm: B = YmX1*YpX2 */
+/* asm 1: fe_mul(>B=fe#2,<YmX1=fe#2,<YpX2=fe#15); */
+/* asm 2: fe_mul(>B=r->Y,<YmX1=r->Y,<YpX2=q->YplusX); */
+fe_mul(r->Y,r->Y,q->YplusX);
+
+/* qhasm: C = T2d2*T1 */
+/* asm 1: fe_mul(>C=fe#4,<T2d2=fe#18,<T1=fe#14); */
+/* asm 2: fe_mul(>C=r->T,<T2d2=q->T2d,<T1=p->T); */
+fe_mul(r->T,q->T2d,p->T);
+
+/* qhasm: ZZ = Z1*Z2 */
+/* asm 1: fe_mul(>ZZ=fe#1,<Z1=fe#13,<Z2=fe#17); */
+/* asm 2: fe_mul(>ZZ=r->X,<Z1=p->Z,<Z2=q->Z); */
+fe_mul(r->X,p->Z,q->Z);
+
+/* qhasm: D = 2*ZZ */
+/* asm 1: fe_add(>D=fe#5,<ZZ=fe#1,<ZZ=fe#1); */
+/* asm 2: fe_add(>D=t0,<ZZ=r->X,<ZZ=r->X); */
+fe_add(t0,r->X,r->X);
+
+/* qhasm: X3 = A-B */
+/* asm 1: fe_sub(>X3=fe#1,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_sub(>X3=r->X,<A=r->Z,<B=r->Y); */
+fe_sub(r->X,r->Z,r->Y);
+
+/* qhasm: Y3 = A+B */
+/* asm 1: fe_add(>Y3=fe#2,<A=fe#3,<B=fe#2); */
+/* asm 2: fe_add(>Y3=r->Y,<A=r->Z,<B=r->Y); */
+fe_add(r->Y,r->Z,r->Y);
+
+/* qhasm: Z3 = D-C */
+/* asm 1: fe_sub(>Z3=fe#3,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_sub(>Z3=r->Z,<D=t0,<C=r->T); */
+fe_sub(r->Z,t0,r->T);
+
+/* qhasm: T3 = D+C */
+/* asm 1: fe_add(>T3=fe#4,<D=fe#5,<C=fe#4); */
+/* asm 2: fe_add(>T3=r->T,<D=t0,<C=r->T); */
+fe_add(r->T,t0,r->T);
+
+/* qhasm: return */
diff --git a/plugin/auth_ed25519/ref10/ge_tobytes.c b/plugin/auth_ed25519/ref10/ge_tobytes.c
new file mode 100644
index 00000000..31b3d33e
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/ge_tobytes.c
@@ -0,0 +1,14 @@
+#include "ge.h"
+
+void ge_tobytes(unsigned char *s,const ge_p2 *h)
+{
+ fe recip;
+ fe x;
+ fe y;
+
+ fe_invert(recip,h->Z);
+ fe_mul(x,h->X,recip);
+ fe_mul(y,h->Y,recip);
+ fe_tobytes(s,y);
+ s[31] ^= fe_isnegative(x) << 7;
+}
diff --git a/plugin/auth_ed25519/ref10/keypair.c b/plugin/auth_ed25519/ref10/keypair.c
new file mode 100644
index 00000000..64000838
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/keypair.c
@@ -0,0 +1,23 @@
+#include <string.h>
+#include "crypto_sign.h"
+#include "crypto_hash_sha512.h"
+#include "ge.h"
+
+int crypto_sign_keypair(
+ unsigned char *pk,
+ unsigned char *pw, unsigned long long pwlen
+)
+{
+ unsigned char az[64];
+ ge_p3 A;
+
+ crypto_hash_sha512(az,pw,pwlen);
+ az[0] &= 248;
+ az[31] &= 63;
+ az[31] |= 64;
+
+ ge_scalarmult_base(&A,az);
+ ge_p3_tobytes(pk,&A);
+
+ return 0;
+}
diff --git a/plugin/auth_ed25519/ref10/open.c b/plugin/auth_ed25519/ref10/open.c
new file mode 100644
index 00000000..7362b681
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/open.c
@@ -0,0 +1,36 @@
+#include <string.h>
+#include "crypto_sign.h"
+#include "crypto_hash_sha512.h"
+#include "crypto_verify_32.h"
+#include "ge.h"
+#include "sc.h"
+
+int crypto_sign_open(
+ unsigned char *sm, unsigned long long smlen,
+ const unsigned char *pk
+)
+{
+ unsigned char scopy[32];
+ unsigned char h[64];
+ unsigned char rcheck[32];
+ ge_p3 A;
+ ge_p2 R;
+
+ if (smlen < 64) goto badsig;
+ if (sm[63] & 224) goto badsig;
+ if (ge_frombytes_negate_vartime(&A,pk) != 0) goto badsig;
+
+ memmove(scopy,sm + 32,32);
+
+ memmove(sm + 32,pk,32);
+ crypto_hash_sha512(h,sm,smlen);
+ sc_reduce(h);
+
+ ge_double_scalarmult_vartime(&R,h,&A,scopy);
+ ge_tobytes(rcheck,&R);
+ if (crypto_verify_32(rcheck,sm) == 0)
+ return 0;
+
+badsig:
+ return -1;
+}
diff --git a/plugin/auth_ed25519/ref10/pow22523.h b/plugin/auth_ed25519/ref10/pow22523.h
new file mode 100644
index 00000000..60ffe0d3
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/pow22523.h
@@ -0,0 +1,160 @@
+
+/* qhasm: fe z1 */
+
+/* qhasm: fe z2 */
+
+/* qhasm: fe z8 */
+
+/* qhasm: fe z9 */
+
+/* qhasm: fe z11 */
+
+/* qhasm: fe z22 */
+
+/* qhasm: fe z_5_0 */
+
+/* qhasm: fe z_10_5 */
+
+/* qhasm: fe z_10_0 */
+
+/* qhasm: fe z_20_10 */
+
+/* qhasm: fe z_20_0 */
+
+/* qhasm: fe z_40_20 */
+
+/* qhasm: fe z_40_0 */
+
+/* qhasm: fe z_50_10 */
+
+/* qhasm: fe z_50_0 */
+
+/* qhasm: fe z_100_50 */
+
+/* qhasm: fe z_100_0 */
+
+/* qhasm: fe z_200_100 */
+
+/* qhasm: fe z_200_0 */
+
+/* qhasm: fe z_250_50 */
+
+/* qhasm: fe z_250_0 */
+
+/* qhasm: fe z_252_2 */
+
+/* qhasm: fe z_252_3 */
+
+/* qhasm: enter pow22523 */
+
+/* qhasm: z2 = z1^2^1 */
+/* asm 1: fe_sq(>z2=fe#1,<z1=fe#11); for (i = 1;i < 1;++i) fe_sq(>z2=fe#1,>z2=fe#1); */
+/* asm 2: fe_sq(>z2=t0,<z1=z); for (i = 1;i < 1;++i) fe_sq(>z2=t0,>z2=t0); */
+fe_sq(t0,z); for (i = 1;i < 1;++i) fe_sq(t0,t0);
+
+/* qhasm: z8 = z2^2^2 */
+/* asm 1: fe_sq(>z8=fe#2,<z2=fe#1); for (i = 1;i < 2;++i) fe_sq(>z8=fe#2,>z8=fe#2); */
+/* asm 2: fe_sq(>z8=t1,<z2=t0); for (i = 1;i < 2;++i) fe_sq(>z8=t1,>z8=t1); */
+fe_sq(t1,t0); for (i = 1;i < 2;++i) fe_sq(t1,t1);
+
+/* qhasm: z9 = z1*z8 */
+/* asm 1: fe_mul(>z9=fe#2,<z1=fe#11,<z8=fe#2); */
+/* asm 2: fe_mul(>z9=t1,<z1=z,<z8=t1); */
+fe_mul(t1,z,t1);
+
+/* qhasm: z11 = z2*z9 */
+/* asm 1: fe_mul(>z11=fe#1,<z2=fe#1,<z9=fe#2); */
+/* asm 2: fe_mul(>z11=t0,<z2=t0,<z9=t1); */
+fe_mul(t0,t0,t1);
+
+/* qhasm: z22 = z11^2^1 */
+/* asm 1: fe_sq(>z22=fe#1,<z11=fe#1); for (i = 1;i < 1;++i) fe_sq(>z22=fe#1,>z22=fe#1); */
+/* asm 2: fe_sq(>z22=t0,<z11=t0); for (i = 1;i < 1;++i) fe_sq(>z22=t0,>z22=t0); */
+fe_sq(t0,t0); for (i = 1;i < 1;++i) fe_sq(t0,t0);
+
+/* qhasm: z_5_0 = z9*z22 */
+/* asm 1: fe_mul(>z_5_0=fe#1,<z9=fe#2,<z22=fe#1); */
+/* asm 2: fe_mul(>z_5_0=t0,<z9=t1,<z22=t0); */
+fe_mul(t0,t1,t0);
+
+/* qhasm: z_10_5 = z_5_0^2^5 */
+/* asm 1: fe_sq(>z_10_5=fe#2,<z_5_0=fe#1); for (i = 1;i < 5;++i) fe_sq(>z_10_5=fe#2,>z_10_5=fe#2); */
+/* asm 2: fe_sq(>z_10_5=t1,<z_5_0=t0); for (i = 1;i < 5;++i) fe_sq(>z_10_5=t1,>z_10_5=t1); */
+fe_sq(t1,t0); for (i = 1;i < 5;++i) fe_sq(t1,t1);
+
+/* qhasm: z_10_0 = z_10_5*z_5_0 */
+/* asm 1: fe_mul(>z_10_0=fe#1,<z_10_5=fe#2,<z_5_0=fe#1); */
+/* asm 2: fe_mul(>z_10_0=t0,<z_10_5=t1,<z_5_0=t0); */
+fe_mul(t0,t1,t0);
+
+/* qhasm: z_20_10 = z_10_0^2^10 */
+/* asm 1: fe_sq(>z_20_10=fe#2,<z_10_0=fe#1); for (i = 1;i < 10;++i) fe_sq(>z_20_10=fe#2,>z_20_10=fe#2); */
+/* asm 2: fe_sq(>z_20_10=t1,<z_10_0=t0); for (i = 1;i < 10;++i) fe_sq(>z_20_10=t1,>z_20_10=t1); */
+fe_sq(t1,t0); for (i = 1;i < 10;++i) fe_sq(t1,t1);
+
+/* qhasm: z_20_0 = z_20_10*z_10_0 */
+/* asm 1: fe_mul(>z_20_0=fe#2,<z_20_10=fe#2,<z_10_0=fe#1); */
+/* asm 2: fe_mul(>z_20_0=t1,<z_20_10=t1,<z_10_0=t0); */
+fe_mul(t1,t1,t0);
+
+/* qhasm: z_40_20 = z_20_0^2^20 */
+/* asm 1: fe_sq(>z_40_20=fe#3,<z_20_0=fe#2); for (i = 1;i < 20;++i) fe_sq(>z_40_20=fe#3,>z_40_20=fe#3); */
+/* asm 2: fe_sq(>z_40_20=t2,<z_20_0=t1); for (i = 1;i < 20;++i) fe_sq(>z_40_20=t2,>z_40_20=t2); */
+fe_sq(t2,t1); for (i = 1;i < 20;++i) fe_sq(t2,t2);
+
+/* qhasm: z_40_0 = z_40_20*z_20_0 */
+/* asm 1: fe_mul(>z_40_0=fe#2,<z_40_20=fe#3,<z_20_0=fe#2); */
+/* asm 2: fe_mul(>z_40_0=t1,<z_40_20=t2,<z_20_0=t1); */
+fe_mul(t1,t2,t1);
+
+/* qhasm: z_50_10 = z_40_0^2^10 */
+/* asm 1: fe_sq(>z_50_10=fe#2,<z_40_0=fe#2); for (i = 1;i < 10;++i) fe_sq(>z_50_10=fe#2,>z_50_10=fe#2); */
+/* asm 2: fe_sq(>z_50_10=t1,<z_40_0=t1); for (i = 1;i < 10;++i) fe_sq(>z_50_10=t1,>z_50_10=t1); */
+fe_sq(t1,t1); for (i = 1;i < 10;++i) fe_sq(t1,t1);
+
+/* qhasm: z_50_0 = z_50_10*z_10_0 */
+/* asm 1: fe_mul(>z_50_0=fe#1,<z_50_10=fe#2,<z_10_0=fe#1); */
+/* asm 2: fe_mul(>z_50_0=t0,<z_50_10=t1,<z_10_0=t0); */
+fe_mul(t0,t1,t0);
+
+/* qhasm: z_100_50 = z_50_0^2^50 */
+/* asm 1: fe_sq(>z_100_50=fe#2,<z_50_0=fe#1); for (i = 1;i < 50;++i) fe_sq(>z_100_50=fe#2,>z_100_50=fe#2); */
+/* asm 2: fe_sq(>z_100_50=t1,<z_50_0=t0); for (i = 1;i < 50;++i) fe_sq(>z_100_50=t1,>z_100_50=t1); */
+fe_sq(t1,t0); for (i = 1;i < 50;++i) fe_sq(t1,t1);
+
+/* qhasm: z_100_0 = z_100_50*z_50_0 */
+/* asm 1: fe_mul(>z_100_0=fe#2,<z_100_50=fe#2,<z_50_0=fe#1); */
+/* asm 2: fe_mul(>z_100_0=t1,<z_100_50=t1,<z_50_0=t0); */
+fe_mul(t1,t1,t0);
+
+/* qhasm: z_200_100 = z_100_0^2^100 */
+/* asm 1: fe_sq(>z_200_100=fe#3,<z_100_0=fe#2); for (i = 1;i < 100;++i) fe_sq(>z_200_100=fe#3,>z_200_100=fe#3); */
+/* asm 2: fe_sq(>z_200_100=t2,<z_100_0=t1); for (i = 1;i < 100;++i) fe_sq(>z_200_100=t2,>z_200_100=t2); */
+fe_sq(t2,t1); for (i = 1;i < 100;++i) fe_sq(t2,t2);
+
+/* qhasm: z_200_0 = z_200_100*z_100_0 */
+/* asm 1: fe_mul(>z_200_0=fe#2,<z_200_100=fe#3,<z_100_0=fe#2); */
+/* asm 2: fe_mul(>z_200_0=t1,<z_200_100=t2,<z_100_0=t1); */
+fe_mul(t1,t2,t1);
+
+/* qhasm: z_250_50 = z_200_0^2^50 */
+/* asm 1: fe_sq(>z_250_50=fe#2,<z_200_0=fe#2); for (i = 1;i < 50;++i) fe_sq(>z_250_50=fe#2,>z_250_50=fe#2); */
+/* asm 2: fe_sq(>z_250_50=t1,<z_200_0=t1); for (i = 1;i < 50;++i) fe_sq(>z_250_50=t1,>z_250_50=t1); */
+fe_sq(t1,t1); for (i = 1;i < 50;++i) fe_sq(t1,t1);
+
+/* qhasm: z_250_0 = z_250_50*z_50_0 */
+/* asm 1: fe_mul(>z_250_0=fe#1,<z_250_50=fe#2,<z_50_0=fe#1); */
+/* asm 2: fe_mul(>z_250_0=t0,<z_250_50=t1,<z_50_0=t0); */
+fe_mul(t0,t1,t0);
+
+/* qhasm: z_252_2 = z_250_0^2^2 */
+/* asm 1: fe_sq(>z_252_2=fe#1,<z_250_0=fe#1); for (i = 1;i < 2;++i) fe_sq(>z_252_2=fe#1,>z_252_2=fe#1); */
+/* asm 2: fe_sq(>z_252_2=t0,<z_250_0=t0); for (i = 1;i < 2;++i) fe_sq(>z_252_2=t0,>z_252_2=t0); */
+fe_sq(t0,t0); for (i = 1;i < 2;++i) fe_sq(t0,t0);
+
+/* qhasm: z_252_3 = z_252_2*z1 */
+/* asm 1: fe_mul(>z_252_3=fe#12,<z_252_2=fe#1,<z1=fe#11); */
+/* asm 2: fe_mul(>z_252_3=out,<z_252_2=t0,<z1=z); */
+fe_mul(out,t0,z);
+
+/* qhasm: return */
diff --git a/plugin/auth_ed25519/ref10/pow225521.h b/plugin/auth_ed25519/ref10/pow225521.h
new file mode 100644
index 00000000..109df779
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/pow225521.h
@@ -0,0 +1,160 @@
+
+/* qhasm: fe z1 */
+
+/* qhasm: fe z2 */
+
+/* qhasm: fe z8 */
+
+/* qhasm: fe z9 */
+
+/* qhasm: fe z11 */
+
+/* qhasm: fe z22 */
+
+/* qhasm: fe z_5_0 */
+
+/* qhasm: fe z_10_5 */
+
+/* qhasm: fe z_10_0 */
+
+/* qhasm: fe z_20_10 */
+
+/* qhasm: fe z_20_0 */
+
+/* qhasm: fe z_40_20 */
+
+/* qhasm: fe z_40_0 */
+
+/* qhasm: fe z_50_10 */
+
+/* qhasm: fe z_50_0 */
+
+/* qhasm: fe z_100_50 */
+
+/* qhasm: fe z_100_0 */
+
+/* qhasm: fe z_200_100 */
+
+/* qhasm: fe z_200_0 */
+
+/* qhasm: fe z_250_50 */
+
+/* qhasm: fe z_250_0 */
+
+/* qhasm: fe z_255_5 */
+
+/* qhasm: fe z_255_21 */
+
+/* qhasm: enter pow225521 */
+
+/* qhasm: z2 = z1^2^1 */
+/* asm 1: fe_sq(>z2=fe#1,<z1=fe#11); for (i = 1;i < 1;++i) fe_sq(>z2=fe#1,>z2=fe#1); */
+/* asm 2: fe_sq(>z2=t0,<z1=z); for (i = 1;i < 1;++i) fe_sq(>z2=t0,>z2=t0); */
+fe_sq(t0,z); for (i = 1;i < 1;++i) fe_sq(t0,t0);
+
+/* qhasm: z8 = z2^2^2 */
+/* asm 1: fe_sq(>z8=fe#2,<z2=fe#1); for (i = 1;i < 2;++i) fe_sq(>z8=fe#2,>z8=fe#2); */
+/* asm 2: fe_sq(>z8=t1,<z2=t0); for (i = 1;i < 2;++i) fe_sq(>z8=t1,>z8=t1); */
+fe_sq(t1,t0); for (i = 1;i < 2;++i) fe_sq(t1,t1);
+
+/* qhasm: z9 = z1*z8 */
+/* asm 1: fe_mul(>z9=fe#2,<z1=fe#11,<z8=fe#2); */
+/* asm 2: fe_mul(>z9=t1,<z1=z,<z8=t1); */
+fe_mul(t1,z,t1);
+
+/* qhasm: z11 = z2*z9 */
+/* asm 1: fe_mul(>z11=fe#1,<z2=fe#1,<z9=fe#2); */
+/* asm 2: fe_mul(>z11=t0,<z2=t0,<z9=t1); */
+fe_mul(t0,t0,t1);
+
+/* qhasm: z22 = z11^2^1 */
+/* asm 1: fe_sq(>z22=fe#3,<z11=fe#1); for (i = 1;i < 1;++i) fe_sq(>z22=fe#3,>z22=fe#3); */
+/* asm 2: fe_sq(>z22=t2,<z11=t0); for (i = 1;i < 1;++i) fe_sq(>z22=t2,>z22=t2); */
+fe_sq(t2,t0); for (i = 1;i < 1;++i) fe_sq(t2,t2);
+
+/* qhasm: z_5_0 = z9*z22 */
+/* asm 1: fe_mul(>z_5_0=fe#2,<z9=fe#2,<z22=fe#3); */
+/* asm 2: fe_mul(>z_5_0=t1,<z9=t1,<z22=t2); */
+fe_mul(t1,t1,t2);
+
+/* qhasm: z_10_5 = z_5_0^2^5 */
+/* asm 1: fe_sq(>z_10_5=fe#3,<z_5_0=fe#2); for (i = 1;i < 5;++i) fe_sq(>z_10_5=fe#3,>z_10_5=fe#3); */
+/* asm 2: fe_sq(>z_10_5=t2,<z_5_0=t1); for (i = 1;i < 5;++i) fe_sq(>z_10_5=t2,>z_10_5=t2); */
+fe_sq(t2,t1); for (i = 1;i < 5;++i) fe_sq(t2,t2);
+
+/* qhasm: z_10_0 = z_10_5*z_5_0 */
+/* asm 1: fe_mul(>z_10_0=fe#2,<z_10_5=fe#3,<z_5_0=fe#2); */
+/* asm 2: fe_mul(>z_10_0=t1,<z_10_5=t2,<z_5_0=t1); */
+fe_mul(t1,t2,t1);
+
+/* qhasm: z_20_10 = z_10_0^2^10 */
+/* asm 1: fe_sq(>z_20_10=fe#3,<z_10_0=fe#2); for (i = 1;i < 10;++i) fe_sq(>z_20_10=fe#3,>z_20_10=fe#3); */
+/* asm 2: fe_sq(>z_20_10=t2,<z_10_0=t1); for (i = 1;i < 10;++i) fe_sq(>z_20_10=t2,>z_20_10=t2); */
+fe_sq(t2,t1); for (i = 1;i < 10;++i) fe_sq(t2,t2);
+
+/* qhasm: z_20_0 = z_20_10*z_10_0 */
+/* asm 1: fe_mul(>z_20_0=fe#3,<z_20_10=fe#3,<z_10_0=fe#2); */
+/* asm 2: fe_mul(>z_20_0=t2,<z_20_10=t2,<z_10_0=t1); */
+fe_mul(t2,t2,t1);
+
+/* qhasm: z_40_20 = z_20_0^2^20 */
+/* asm 1: fe_sq(>z_40_20=fe#4,<z_20_0=fe#3); for (i = 1;i < 20;++i) fe_sq(>z_40_20=fe#4,>z_40_20=fe#4); */
+/* asm 2: fe_sq(>z_40_20=t3,<z_20_0=t2); for (i = 1;i < 20;++i) fe_sq(>z_40_20=t3,>z_40_20=t3); */
+fe_sq(t3,t2); for (i = 1;i < 20;++i) fe_sq(t3,t3);
+
+/* qhasm: z_40_0 = z_40_20*z_20_0 */
+/* asm 1: fe_mul(>z_40_0=fe#3,<z_40_20=fe#4,<z_20_0=fe#3); */
+/* asm 2: fe_mul(>z_40_0=t2,<z_40_20=t3,<z_20_0=t2); */
+fe_mul(t2,t3,t2);
+
+/* qhasm: z_50_10 = z_40_0^2^10 */
+/* asm 1: fe_sq(>z_50_10=fe#3,<z_40_0=fe#3); for (i = 1;i < 10;++i) fe_sq(>z_50_10=fe#3,>z_50_10=fe#3); */
+/* asm 2: fe_sq(>z_50_10=t2,<z_40_0=t2); for (i = 1;i < 10;++i) fe_sq(>z_50_10=t2,>z_50_10=t2); */
+fe_sq(t2,t2); for (i = 1;i < 10;++i) fe_sq(t2,t2);
+
+/* qhasm: z_50_0 = z_50_10*z_10_0 */
+/* asm 1: fe_mul(>z_50_0=fe#2,<z_50_10=fe#3,<z_10_0=fe#2); */
+/* asm 2: fe_mul(>z_50_0=t1,<z_50_10=t2,<z_10_0=t1); */
+fe_mul(t1,t2,t1);
+
+/* qhasm: z_100_50 = z_50_0^2^50 */
+/* asm 1: fe_sq(>z_100_50=fe#3,<z_50_0=fe#2); for (i = 1;i < 50;++i) fe_sq(>z_100_50=fe#3,>z_100_50=fe#3); */
+/* asm 2: fe_sq(>z_100_50=t2,<z_50_0=t1); for (i = 1;i < 50;++i) fe_sq(>z_100_50=t2,>z_100_50=t2); */
+fe_sq(t2,t1); for (i = 1;i < 50;++i) fe_sq(t2,t2);
+
+/* qhasm: z_100_0 = z_100_50*z_50_0 */
+/* asm 1: fe_mul(>z_100_0=fe#3,<z_100_50=fe#3,<z_50_0=fe#2); */
+/* asm 2: fe_mul(>z_100_0=t2,<z_100_50=t2,<z_50_0=t1); */
+fe_mul(t2,t2,t1);
+
+/* qhasm: z_200_100 = z_100_0^2^100 */
+/* asm 1: fe_sq(>z_200_100=fe#4,<z_100_0=fe#3); for (i = 1;i < 100;++i) fe_sq(>z_200_100=fe#4,>z_200_100=fe#4); */
+/* asm 2: fe_sq(>z_200_100=t3,<z_100_0=t2); for (i = 1;i < 100;++i) fe_sq(>z_200_100=t3,>z_200_100=t3); */
+fe_sq(t3,t2); for (i = 1;i < 100;++i) fe_sq(t3,t3);
+
+/* qhasm: z_200_0 = z_200_100*z_100_0 */
+/* asm 1: fe_mul(>z_200_0=fe#3,<z_200_100=fe#4,<z_100_0=fe#3); */
+/* asm 2: fe_mul(>z_200_0=t2,<z_200_100=t3,<z_100_0=t2); */
+fe_mul(t2,t3,t2);
+
+/* qhasm: z_250_50 = z_200_0^2^50 */
+/* asm 1: fe_sq(>z_250_50=fe#3,<z_200_0=fe#3); for (i = 1;i < 50;++i) fe_sq(>z_250_50=fe#3,>z_250_50=fe#3); */
+/* asm 2: fe_sq(>z_250_50=t2,<z_200_0=t2); for (i = 1;i < 50;++i) fe_sq(>z_250_50=t2,>z_250_50=t2); */
+fe_sq(t2,t2); for (i = 1;i < 50;++i) fe_sq(t2,t2);
+
+/* qhasm: z_250_0 = z_250_50*z_50_0 */
+/* asm 1: fe_mul(>z_250_0=fe#2,<z_250_50=fe#3,<z_50_0=fe#2); */
+/* asm 2: fe_mul(>z_250_0=t1,<z_250_50=t2,<z_50_0=t1); */
+fe_mul(t1,t2,t1);
+
+/* qhasm: z_255_5 = z_250_0^2^5 */
+/* asm 1: fe_sq(>z_255_5=fe#2,<z_250_0=fe#2); for (i = 1;i < 5;++i) fe_sq(>z_255_5=fe#2,>z_255_5=fe#2); */
+/* asm 2: fe_sq(>z_255_5=t1,<z_250_0=t1); for (i = 1;i < 5;++i) fe_sq(>z_255_5=t1,>z_255_5=t1); */
+fe_sq(t1,t1); for (i = 1;i < 5;++i) fe_sq(t1,t1);
+
+/* qhasm: z_255_21 = z_255_5*z11 */
+/* asm 1: fe_mul(>z_255_21=fe#12,<z_255_5=fe#2,<z11=fe#1); */
+/* asm 2: fe_mul(>z_255_21=out,<z_255_5=t1,<z11=t0); */
+fe_mul(out,t1,t0);
+
+/* qhasm: return */
diff --git a/plugin/auth_ed25519/ref10/sc.h b/plugin/auth_ed25519/ref10/sc.h
new file mode 100644
index 00000000..d32ed2e8
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/sc.h
@@ -0,0 +1,15 @@
+#ifndef SC_H
+#define SC_H
+
+/*
+The set of scalars is \Z/l
+where l = 2^252 + 27742317777372353535851937790883648493.
+*/
+
+#define sc_reduce crypto_sign_ed25519_ref10_sc_reduce
+#define sc_muladd crypto_sign_ed25519_ref10_sc_muladd
+
+extern void sc_reduce(unsigned char *);
+extern void sc_muladd(unsigned char *,const unsigned char *,const unsigned char *,const unsigned char *);
+
+#endif
diff --git a/plugin/auth_ed25519/ref10/sc_muladd.c b/plugin/auth_ed25519/ref10/sc_muladd.c
new file mode 100644
index 00000000..6f1e9d02
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/sc_muladd.c
@@ -0,0 +1,368 @@
+#include "sc.h"
+#include "crypto_int64.h"
+#include "crypto_uint32.h"
+#include "crypto_uint64.h"
+
+static crypto_uint64 load_3(const unsigned char *in)
+{
+ crypto_uint64 result;
+ result = (crypto_uint64) in[0];
+ result |= ((crypto_uint64) in[1]) << 8;
+ result |= ((crypto_uint64) in[2]) << 16;
+ return result;
+}
+
+static crypto_uint64 load_4(const unsigned char *in)
+{
+ crypto_uint64 result;
+ result = (crypto_uint64) in[0];
+ result |= ((crypto_uint64) in[1]) << 8;
+ result |= ((crypto_uint64) in[2]) << 16;
+ result |= ((crypto_uint64) in[3]) << 24;
+ return result;
+}
+
+/*
+Input:
+ a[0]+256*a[1]+...+256^31*a[31] = a
+ b[0]+256*b[1]+...+256^31*b[31] = b
+ c[0]+256*c[1]+...+256^31*c[31] = c
+
+Output:
+ s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l
+ where l = 2^252 + 27742317777372353535851937790883648493.
+*/
+
+void sc_muladd(unsigned char *s,const unsigned char *a,const unsigned char *b,const unsigned char *c)
+{
+ crypto_int64 a0 = 2097151 & load_3(a);
+ crypto_int64 a1 = 2097151 & (load_4(a + 2) >> 5);
+ crypto_int64 a2 = 2097151 & (load_3(a + 5) >> 2);
+ crypto_int64 a3 = 2097151 & (load_4(a + 7) >> 7);
+ crypto_int64 a4 = 2097151 & (load_4(a + 10) >> 4);
+ crypto_int64 a5 = 2097151 & (load_3(a + 13) >> 1);
+ crypto_int64 a6 = 2097151 & (load_4(a + 15) >> 6);
+ crypto_int64 a7 = 2097151 & (load_3(a + 18) >> 3);
+ crypto_int64 a8 = 2097151 & load_3(a + 21);
+ crypto_int64 a9 = 2097151 & (load_4(a + 23) >> 5);
+ crypto_int64 a10 = 2097151 & (load_3(a + 26) >> 2);
+ crypto_int64 a11 = (load_4(a + 28) >> 7);
+ crypto_int64 b0 = 2097151 & load_3(b);
+ crypto_int64 b1 = 2097151 & (load_4(b + 2) >> 5);
+ crypto_int64 b2 = 2097151 & (load_3(b + 5) >> 2);
+ crypto_int64 b3 = 2097151 & (load_4(b + 7) >> 7);
+ crypto_int64 b4 = 2097151 & (load_4(b + 10) >> 4);
+ crypto_int64 b5 = 2097151 & (load_3(b + 13) >> 1);
+ crypto_int64 b6 = 2097151 & (load_4(b + 15) >> 6);
+ crypto_int64 b7 = 2097151 & (load_3(b + 18) >> 3);
+ crypto_int64 b8 = 2097151 & load_3(b + 21);
+ crypto_int64 b9 = 2097151 & (load_4(b + 23) >> 5);
+ crypto_int64 b10 = 2097151 & (load_3(b + 26) >> 2);
+ crypto_int64 b11 = (load_4(b + 28) >> 7);
+ crypto_int64 c0 = 2097151 & load_3(c);
+ crypto_int64 c1 = 2097151 & (load_4(c + 2) >> 5);
+ crypto_int64 c2 = 2097151 & (load_3(c + 5) >> 2);
+ crypto_int64 c3 = 2097151 & (load_4(c + 7) >> 7);
+ crypto_int64 c4 = 2097151 & (load_4(c + 10) >> 4);
+ crypto_int64 c5 = 2097151 & (load_3(c + 13) >> 1);
+ crypto_int64 c6 = 2097151 & (load_4(c + 15) >> 6);
+ crypto_int64 c7 = 2097151 & (load_3(c + 18) >> 3);
+ crypto_int64 c8 = 2097151 & load_3(c + 21);
+ crypto_int64 c9 = 2097151 & (load_4(c + 23) >> 5);
+ crypto_int64 c10 = 2097151 & (load_3(c + 26) >> 2);
+ crypto_int64 c11 = (load_4(c + 28) >> 7);
+ crypto_int64 s0;
+ crypto_int64 s1;
+ crypto_int64 s2;
+ crypto_int64 s3;
+ crypto_int64 s4;
+ crypto_int64 s5;
+ crypto_int64 s6;
+ crypto_int64 s7;
+ crypto_int64 s8;
+ crypto_int64 s9;
+ crypto_int64 s10;
+ crypto_int64 s11;
+ crypto_int64 s12;
+ crypto_int64 s13;
+ crypto_int64 s14;
+ crypto_int64 s15;
+ crypto_int64 s16;
+ crypto_int64 s17;
+ crypto_int64 s18;
+ crypto_int64 s19;
+ crypto_int64 s20;
+ crypto_int64 s21;
+ crypto_int64 s22;
+ crypto_int64 s23;
+ crypto_int64 carry0;
+ crypto_int64 carry1;
+ crypto_int64 carry2;
+ crypto_int64 carry3;
+ crypto_int64 carry4;
+ crypto_int64 carry5;
+ crypto_int64 carry6;
+ crypto_int64 carry7;
+ crypto_int64 carry8;
+ crypto_int64 carry9;
+ crypto_int64 carry10;
+ crypto_int64 carry11;
+ crypto_int64 carry12;
+ crypto_int64 carry13;
+ crypto_int64 carry14;
+ crypto_int64 carry15;
+ crypto_int64 carry16;
+ crypto_int64 carry17;
+ crypto_int64 carry18;
+ crypto_int64 carry19;
+ crypto_int64 carry20;
+ crypto_int64 carry21;
+ crypto_int64 carry22;
+
+ s0 = c0 + a0*b0;
+ s1 = c1 + a0*b1 + a1*b0;
+ s2 = c2 + a0*b2 + a1*b1 + a2*b0;
+ s3 = c3 + a0*b3 + a1*b2 + a2*b1 + a3*b0;
+ s4 = c4 + a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0;
+ s5 = c5 + a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0;
+ s6 = c6 + a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0;
+ s7 = c7 + a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0;
+ s8 = c8 + a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0;
+ s9 = c9 + a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0;
+ s10 = c10 + a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0;
+ s11 = c11 + a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0;
+ s12 = a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1;
+ s13 = a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2;
+ s14 = a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3;
+ s15 = a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4;
+ s16 = a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5;
+ s17 = a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6;
+ s18 = a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7;
+ s19 = a8*b11 + a9*b10 + a10*b9 + a11*b8;
+ s20 = a9*b11 + a10*b10 + a11*b9;
+ s21 = a10*b11 + a11*b10;
+ s22 = a11*b11;
+ s23 = 0;
+
+ carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+ carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+ carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+ carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+ carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+ carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+ carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+ carry18 = (s18 + (1<<20)) >> 21; s19 += carry18; s18 -= carry18 << 21;
+ carry20 = (s20 + (1<<20)) >> 21; s21 += carry20; s20 -= carry20 << 21;
+ carry22 = (s22 + (1<<20)) >> 21; s23 += carry22; s22 -= carry22 << 21;
+
+ carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+ carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+ carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+ carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+ carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+ carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+ carry17 = (s17 + (1<<20)) >> 21; s18 += carry17; s17 -= carry17 << 21;
+ carry19 = (s19 + (1<<20)) >> 21; s20 += carry19; s19 -= carry19 << 21;
+ carry21 = (s21 + (1<<20)) >> 21; s22 += carry21; s21 -= carry21 << 21;
+
+ s11 += s23 * 666643;
+ s12 += s23 * 470296;
+ s13 += s23 * 654183;
+ s14 -= s23 * 997805;
+ s15 += s23 * 136657;
+ s16 -= s23 * 683901;
+ s23 = 0;
+
+ s10 += s22 * 666643;
+ s11 += s22 * 470296;
+ s12 += s22 * 654183;
+ s13 -= s22 * 997805;
+ s14 += s22 * 136657;
+ s15 -= s22 * 683901;
+ s22 = 0;
+
+ s9 += s21 * 666643;
+ s10 += s21 * 470296;
+ s11 += s21 * 654183;
+ s12 -= s21 * 997805;
+ s13 += s21 * 136657;
+ s14 -= s21 * 683901;
+ s21 = 0;
+
+ s8 += s20 * 666643;
+ s9 += s20 * 470296;
+ s10 += s20 * 654183;
+ s11 -= s20 * 997805;
+ s12 += s20 * 136657;
+ s13 -= s20 * 683901;
+ s20 = 0;
+
+ s7 += s19 * 666643;
+ s8 += s19 * 470296;
+ s9 += s19 * 654183;
+ s10 -= s19 * 997805;
+ s11 += s19 * 136657;
+ s12 -= s19 * 683901;
+ s19 = 0;
+
+ s6 += s18 * 666643;
+ s7 += s18 * 470296;
+ s8 += s18 * 654183;
+ s9 -= s18 * 997805;
+ s10 += s18 * 136657;
+ s11 -= s18 * 683901;
+ s18 = 0;
+
+ carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+ carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+ carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+ carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+
+ carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+ carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+ carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+
+ s5 += s17 * 666643;
+ s6 += s17 * 470296;
+ s7 += s17 * 654183;
+ s8 -= s17 * 997805;
+ s9 += s17 * 136657;
+ s10 -= s17 * 683901;
+ s17 = 0;
+
+ s4 += s16 * 666643;
+ s5 += s16 * 470296;
+ s6 += s16 * 654183;
+ s7 -= s16 * 997805;
+ s8 += s16 * 136657;
+ s9 -= s16 * 683901;
+ s16 = 0;
+
+ s3 += s15 * 666643;
+ s4 += s15 * 470296;
+ s5 += s15 * 654183;
+ s6 -= s15 * 997805;
+ s7 += s15 * 136657;
+ s8 -= s15 * 683901;
+ s15 = 0;
+
+ s2 += s14 * 666643;
+ s3 += s14 * 470296;
+ s4 += s14 * 654183;
+ s5 -= s14 * 997805;
+ s6 += s14 * 136657;
+ s7 -= s14 * 683901;
+ s14 = 0;
+
+ s1 += s13 * 666643;
+ s2 += s13 * 470296;
+ s3 += s13 * 654183;
+ s4 -= s13 * 997805;
+ s5 += s13 * 136657;
+ s6 -= s13 * 683901;
+ s13 = 0;
+
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+
+ carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+ carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+ carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+ carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+ carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+ carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+ carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+ carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+
+ carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+ carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+ carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+ carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+ carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+ carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+ carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+ carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+
+ carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+ carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+ carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+ carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+ carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+ carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+ carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+ s[0] = s0 >> 0;
+ s[1] = s0 >> 8;
+ s[2] = (s0 >> 16) | (s1 << 5);
+ s[3] = s1 >> 3;
+ s[4] = s1 >> 11;
+ s[5] = (s1 >> 19) | (s2 << 2);
+ s[6] = s2 >> 6;
+ s[7] = (s2 >> 14) | (s3 << 7);
+ s[8] = s3 >> 1;
+ s[9] = s3 >> 9;
+ s[10] = (s3 >> 17) | (s4 << 4);
+ s[11] = s4 >> 4;
+ s[12] = s4 >> 12;
+ s[13] = (s4 >> 20) | (s5 << 1);
+ s[14] = s5 >> 7;
+ s[15] = (s5 >> 15) | (s6 << 6);
+ s[16] = s6 >> 2;
+ s[17] = s6 >> 10;
+ s[18] = (s6 >> 18) | (s7 << 3);
+ s[19] = s7 >> 5;
+ s[20] = s7 >> 13;
+ s[21] = s8 >> 0;
+ s[22] = s8 >> 8;
+ s[23] = (s8 >> 16) | (s9 << 5);
+ s[24] = s9 >> 3;
+ s[25] = s9 >> 11;
+ s[26] = (s9 >> 19) | (s10 << 2);
+ s[27] = s10 >> 6;
+ s[28] = (s10 >> 14) | (s11 << 7);
+ s[29] = s11 >> 1;
+ s[30] = s11 >> 9;
+ s[31] = s11 >> 17;
+}
diff --git a/plugin/auth_ed25519/ref10/sc_reduce.c b/plugin/auth_ed25519/ref10/sc_reduce.c
new file mode 100644
index 00000000..d01f5a57
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/sc_reduce.c
@@ -0,0 +1,275 @@
+#include "sc.h"
+#include "crypto_int64.h"
+#include "crypto_uint32.h"
+#include "crypto_uint64.h"
+
+static crypto_uint64 load_3(const unsigned char *in)
+{
+ crypto_uint64 result;
+ result = (crypto_uint64) in[0];
+ result |= ((crypto_uint64) in[1]) << 8;
+ result |= ((crypto_uint64) in[2]) << 16;
+ return result;
+}
+
+static crypto_uint64 load_4(const unsigned char *in)
+{
+ crypto_uint64 result;
+ result = (crypto_uint64) in[0];
+ result |= ((crypto_uint64) in[1]) << 8;
+ result |= ((crypto_uint64) in[2]) << 16;
+ result |= ((crypto_uint64) in[3]) << 24;
+ return result;
+}
+
+/*
+Input:
+ s[0]+256*s[1]+...+256^63*s[63] = s
+
+Output:
+ s[0]+256*s[1]+...+256^31*s[31] = s mod l
+ where l = 2^252 + 27742317777372353535851937790883648493.
+ Overwrites s in place.
+*/
+
+void sc_reduce(unsigned char *s)
+{
+ crypto_int64 s0 = 2097151 & load_3(s);
+ crypto_int64 s1 = 2097151 & (load_4(s + 2) >> 5);
+ crypto_int64 s2 = 2097151 & (load_3(s + 5) >> 2);
+ crypto_int64 s3 = 2097151 & (load_4(s + 7) >> 7);
+ crypto_int64 s4 = 2097151 & (load_4(s + 10) >> 4);
+ crypto_int64 s5 = 2097151 & (load_3(s + 13) >> 1);
+ crypto_int64 s6 = 2097151 & (load_4(s + 15) >> 6);
+ crypto_int64 s7 = 2097151 & (load_3(s + 18) >> 3);
+ crypto_int64 s8 = 2097151 & load_3(s + 21);
+ crypto_int64 s9 = 2097151 & (load_4(s + 23) >> 5);
+ crypto_int64 s10 = 2097151 & (load_3(s + 26) >> 2);
+ crypto_int64 s11 = 2097151 & (load_4(s + 28) >> 7);
+ crypto_int64 s12 = 2097151 & (load_4(s + 31) >> 4);
+ crypto_int64 s13 = 2097151 & (load_3(s + 34) >> 1);
+ crypto_int64 s14 = 2097151 & (load_4(s + 36) >> 6);
+ crypto_int64 s15 = 2097151 & (load_3(s + 39) >> 3);
+ crypto_int64 s16 = 2097151 & load_3(s + 42);
+ crypto_int64 s17 = 2097151 & (load_4(s + 44) >> 5);
+ crypto_int64 s18 = 2097151 & (load_3(s + 47) >> 2);
+ crypto_int64 s19 = 2097151 & (load_4(s + 49) >> 7);
+ crypto_int64 s20 = 2097151 & (load_4(s + 52) >> 4);
+ crypto_int64 s21 = 2097151 & (load_3(s + 55) >> 1);
+ crypto_int64 s22 = 2097151 & (load_4(s + 57) >> 6);
+ crypto_int64 s23 = (load_4(s + 60) >> 3);
+ crypto_int64 carry0;
+ crypto_int64 carry1;
+ crypto_int64 carry2;
+ crypto_int64 carry3;
+ crypto_int64 carry4;
+ crypto_int64 carry5;
+ crypto_int64 carry6;
+ crypto_int64 carry7;
+ crypto_int64 carry8;
+ crypto_int64 carry9;
+ crypto_int64 carry10;
+ crypto_int64 carry11;
+ crypto_int64 carry12;
+ crypto_int64 carry13;
+ crypto_int64 carry14;
+ crypto_int64 carry15;
+ crypto_int64 carry16;
+
+ s11 += s23 * 666643;
+ s12 += s23 * 470296;
+ s13 += s23 * 654183;
+ s14 -= s23 * 997805;
+ s15 += s23 * 136657;
+ s16 -= s23 * 683901;
+ s23 = 0;
+
+ s10 += s22 * 666643;
+ s11 += s22 * 470296;
+ s12 += s22 * 654183;
+ s13 -= s22 * 997805;
+ s14 += s22 * 136657;
+ s15 -= s22 * 683901;
+ s22 = 0;
+
+ s9 += s21 * 666643;
+ s10 += s21 * 470296;
+ s11 += s21 * 654183;
+ s12 -= s21 * 997805;
+ s13 += s21 * 136657;
+ s14 -= s21 * 683901;
+ s21 = 0;
+
+ s8 += s20 * 666643;
+ s9 += s20 * 470296;
+ s10 += s20 * 654183;
+ s11 -= s20 * 997805;
+ s12 += s20 * 136657;
+ s13 -= s20 * 683901;
+ s20 = 0;
+
+ s7 += s19 * 666643;
+ s8 += s19 * 470296;
+ s9 += s19 * 654183;
+ s10 -= s19 * 997805;
+ s11 += s19 * 136657;
+ s12 -= s19 * 683901;
+ s19 = 0;
+
+ s6 += s18 * 666643;
+ s7 += s18 * 470296;
+ s8 += s18 * 654183;
+ s9 -= s18 * 997805;
+ s10 += s18 * 136657;
+ s11 -= s18 * 683901;
+ s18 = 0;
+
+ carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+ carry12 = (s12 + (1<<20)) >> 21; s13 += carry12; s12 -= carry12 << 21;
+ carry14 = (s14 + (1<<20)) >> 21; s15 += carry14; s14 -= carry14 << 21;
+ carry16 = (s16 + (1<<20)) >> 21; s17 += carry16; s16 -= carry16 << 21;
+
+ carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+ carry13 = (s13 + (1<<20)) >> 21; s14 += carry13; s13 -= carry13 << 21;
+ carry15 = (s15 + (1<<20)) >> 21; s16 += carry15; s15 -= carry15 << 21;
+
+ s5 += s17 * 666643;
+ s6 += s17 * 470296;
+ s7 += s17 * 654183;
+ s8 -= s17 * 997805;
+ s9 += s17 * 136657;
+ s10 -= s17 * 683901;
+ s17 = 0;
+
+ s4 += s16 * 666643;
+ s5 += s16 * 470296;
+ s6 += s16 * 654183;
+ s7 -= s16 * 997805;
+ s8 += s16 * 136657;
+ s9 -= s16 * 683901;
+ s16 = 0;
+
+ s3 += s15 * 666643;
+ s4 += s15 * 470296;
+ s5 += s15 * 654183;
+ s6 -= s15 * 997805;
+ s7 += s15 * 136657;
+ s8 -= s15 * 683901;
+ s15 = 0;
+
+ s2 += s14 * 666643;
+ s3 += s14 * 470296;
+ s4 += s14 * 654183;
+ s5 -= s14 * 997805;
+ s6 += s14 * 136657;
+ s7 -= s14 * 683901;
+ s14 = 0;
+
+ s1 += s13 * 666643;
+ s2 += s13 * 470296;
+ s3 += s13 * 654183;
+ s4 -= s13 * 997805;
+ s5 += s13 * 136657;
+ s6 -= s13 * 683901;
+ s13 = 0;
+
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+
+ carry0 = (s0 + (1<<20)) >> 21; s1 += carry0; s0 -= carry0 << 21;
+ carry2 = (s2 + (1<<20)) >> 21; s3 += carry2; s2 -= carry2 << 21;
+ carry4 = (s4 + (1<<20)) >> 21; s5 += carry4; s4 -= carry4 << 21;
+ carry6 = (s6 + (1<<20)) >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry8 = (s8 + (1<<20)) >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry10 = (s10 + (1<<20)) >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+ carry1 = (s1 + (1<<20)) >> 21; s2 += carry1; s1 -= carry1 << 21;
+ carry3 = (s3 + (1<<20)) >> 21; s4 += carry3; s3 -= carry3 << 21;
+ carry5 = (s5 + (1<<20)) >> 21; s6 += carry5; s5 -= carry5 << 21;
+ carry7 = (s7 + (1<<20)) >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry9 = (s9 + (1<<20)) >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry11 = (s11 + (1<<20)) >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+
+ carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+ carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+ carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+ carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+ carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+ carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+ carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+ carry11 = s11 >> 21; s12 += carry11; s11 -= carry11 << 21;
+
+ s0 += s12 * 666643;
+ s1 += s12 * 470296;
+ s2 += s12 * 654183;
+ s3 -= s12 * 997805;
+ s4 += s12 * 136657;
+ s5 -= s12 * 683901;
+ s12 = 0;
+
+ carry0 = s0 >> 21; s1 += carry0; s0 -= carry0 << 21;
+ carry1 = s1 >> 21; s2 += carry1; s1 -= carry1 << 21;
+ carry2 = s2 >> 21; s3 += carry2; s2 -= carry2 << 21;
+ carry3 = s3 >> 21; s4 += carry3; s3 -= carry3 << 21;
+ carry4 = s4 >> 21; s5 += carry4; s4 -= carry4 << 21;
+ carry5 = s5 >> 21; s6 += carry5; s5 -= carry5 << 21;
+ carry6 = s6 >> 21; s7 += carry6; s6 -= carry6 << 21;
+ carry7 = s7 >> 21; s8 += carry7; s7 -= carry7 << 21;
+ carry8 = s8 >> 21; s9 += carry8; s8 -= carry8 << 21;
+ carry9 = s9 >> 21; s10 += carry9; s9 -= carry9 << 21;
+ carry10 = s10 >> 21; s11 += carry10; s10 -= carry10 << 21;
+
+ s[0] = s0 >> 0;
+ s[1] = s0 >> 8;
+ s[2] = (s0 >> 16) | (s1 << 5);
+ s[3] = s1 >> 3;
+ s[4] = s1 >> 11;
+ s[5] = (s1 >> 19) | (s2 << 2);
+ s[6] = s2 >> 6;
+ s[7] = (s2 >> 14) | (s3 << 7);
+ s[8] = s3 >> 1;
+ s[9] = s3 >> 9;
+ s[10] = (s3 >> 17) | (s4 << 4);
+ s[11] = s4 >> 4;
+ s[12] = s4 >> 12;
+ s[13] = (s4 >> 20) | (s5 << 1);
+ s[14] = s5 >> 7;
+ s[15] = (s5 >> 15) | (s6 << 6);
+ s[16] = s6 >> 2;
+ s[17] = s6 >> 10;
+ s[18] = (s6 >> 18) | (s7 << 3);
+ s[19] = s7 >> 5;
+ s[20] = s7 >> 13;
+ s[21] = s8 >> 0;
+ s[22] = s8 >> 8;
+ s[23] = (s8 >> 16) | (s9 << 5);
+ s[24] = s9 >> 3;
+ s[25] = s9 >> 11;
+ s[26] = (s9 >> 19) | (s10 << 2);
+ s[27] = s10 >> 6;
+ s[28] = (s10 >> 14) | (s11 << 7);
+ s[29] = s11 >> 1;
+ s[30] = s11 >> 9;
+ s[31] = s11 >> 17;
+}
diff --git a/plugin/auth_ed25519/ref10/sign.c b/plugin/auth_ed25519/ref10/sign.c
new file mode 100644
index 00000000..0cf1edd1
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/sign.c
@@ -0,0 +1,39 @@
+#include <string.h>
+#include "crypto_sign.h"
+#include "crypto_hash_sha512.h"
+#include "ge.h"
+#include "sc.h"
+
+int crypto_sign(
+ unsigned char *sm,
+ const unsigned char *m,unsigned long long mlen,
+ const unsigned char *pw,unsigned long long pwlen
+)
+{
+ unsigned char az[64];
+ unsigned char nonce[64];
+ unsigned char hram[64];
+ ge_p3 A, R;
+
+ crypto_hash_sha512(az,pw,pwlen);
+ az[0] &= 248;
+ az[31] &= 63;
+ az[31] |= 64;
+
+ memmove(sm + 64,m,mlen);
+ memmove(sm + 32,az + 32,32);
+ crypto_hash_sha512(nonce,sm + 32,mlen + 32);
+
+ ge_scalarmult_base(&A,az);
+ ge_p3_tobytes(sm + 32,&A);
+
+ sc_reduce(nonce);
+ ge_scalarmult_base(&R,nonce);
+ ge_p3_tobytes(sm,&R);
+
+ crypto_hash_sha512(hram,sm,mlen + 64);
+ sc_reduce(hram);
+ sc_muladd(sm + 32,hram,az,nonce);
+
+ return 0;
+}
diff --git a/plugin/auth_ed25519/ref10/sqrtm1.h b/plugin/auth_ed25519/ref10/sqrtm1.h
new file mode 100644
index 00000000..d8caa23b
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/sqrtm1.h
@@ -0,0 +1 @@
+-32595792,-7943725,9377950,3500415,12389472,-272473,-25146209,-2005654,326686,11406482
diff --git a/plugin/auth_ed25519/ref10/verify.c b/plugin/auth_ed25519/ref10/verify.c
new file mode 100644
index 00000000..a0e23afe
--- /dev/null
+++ b/plugin/auth_ed25519/ref10/verify.c
@@ -0,0 +1,40 @@
+#include "crypto_verify.h"
+
+int crypto_verify(const unsigned char *x,const unsigned char *y)
+{
+ unsigned int differentbits = 0;
+#define F(i) differentbits |= x[i] ^ y[i];
+ F(0)
+ F(1)
+ F(2)
+ F(3)
+ F(4)
+ F(5)
+ F(6)
+ F(7)
+ F(8)
+ F(9)
+ F(10)
+ F(11)
+ F(12)
+ F(13)
+ F(14)
+ F(15)
+ F(16)
+ F(17)
+ F(18)
+ F(19)
+ F(20)
+ F(21)
+ F(22)
+ F(23)
+ F(24)
+ F(25)
+ F(26)
+ F(27)
+ F(28)
+ F(29)
+ F(30)
+ F(31)
+ return (1 & ((differentbits - 1) >> 8)) - 1;
+}
diff --git a/plugin/auth_ed25519/server_ed25519.c b/plugin/auth_ed25519/server_ed25519.c
new file mode 100644
index 00000000..b789bd34
--- /dev/null
+++ b/plugin/auth_ed25519/server_ed25519.c
@@ -0,0 +1,171 @@
+/*
+ Copyright (c) 2017, 2021, MariaDB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include <mysql/plugin_auth.h>
+#include <mysqld_error.h>
+#include "common.h"
+
+#if !defined(__attribute__) && !defined(__GNUC__)
+#define __attribute__(A)
+#endif
+
+#define PASSWORD_LEN_BUF 44 /* base64 of 32 bytes */
+#define PASSWORD_LEN 43 /* we won't store the last byte, padding '=' */
+
+#define CRYPTO_LONGS (CRYPTO_BYTES/sizeof(long))
+#define NONCE_LONGS (NONCE_BYTES/sizeof(long))
+
+/************************** SERVER *************************************/
+
+static int loaded= 0;
+
+static int auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
+{
+ int pkt_len;
+ unsigned long nonce[CRYPTO_LONGS + NONCE_LONGS];
+ unsigned char *pkt, *reply= (unsigned char*)nonce;
+
+ info->password_used= PASSWORD_USED_YES;
+
+ /* prepare random nonce */
+ if (my_random_bytes((unsigned char *)nonce, (int)sizeof(nonce)))
+ return CR_ERROR; // eh? OpenSSL error
+
+ /* send it */
+ if (vio->write_packet(vio, reply + CRYPTO_BYTES, NONCE_BYTES))
+ return CR_AUTH_HANDSHAKE;
+
+ /* read the signature */
+ if ((pkt_len= vio->read_packet(vio, &pkt)) != CRYPTO_BYTES)
+ return CR_AUTH_HANDSHAKE;
+ memcpy(reply, pkt, CRYPTO_BYTES);
+
+ if (crypto_sign_open(reply, CRYPTO_BYTES + NONCE_BYTES,
+ (unsigned char*)info->auth_string))
+ return CR_AUTH_USER_CREDENTIALS; // wrong password provided by the user
+
+ return CR_OK;
+}
+
+static int compute_password_digest(const char *pw, size_t pwlen,
+ char *d, size_t *dlen)
+{
+ unsigned char pk[CRYPTO_PUBLICKEYBYTES];
+ if (*dlen < PASSWORD_LEN || pwlen == 0)
+ return 1;
+ *dlen= PASSWORD_LEN;
+ crypto_sign_keypair(pk, (unsigned char*)pw, pwlen);
+ my_base64_encode(pk, CRYPTO_PUBLICKEYBYTES, d);
+ return 0;
+}
+
+static int digest_to_binary(const char *d, size_t dlen,
+ unsigned char *b, size_t *blen)
+{
+ char pw[PASSWORD_LEN_BUF];
+
+ if (*blen < CRYPTO_PUBLICKEYBYTES || dlen != PASSWORD_LEN)
+ {
+ my_printf_error(ER_PASSWD_LENGTH, "Password hash should be %d characters long", 0, PASSWORD_LEN);
+ return 1;
+ }
+
+ *blen= CRYPTO_PUBLICKEYBYTES;
+ memcpy(pw, d, PASSWORD_LEN);
+ pw[PASSWORD_LEN]= '=';
+ if (my_base64_decode(pw, PASSWORD_LEN_BUF, b, 0, 0) == CRYPTO_PUBLICKEYBYTES)
+ return 0;
+ my_printf_error(ER_PASSWD_LENGTH, "Password hash should be base64 encoded", 0);
+ return 1;
+}
+
+static struct st_mysql_auth info =
+{
+ MYSQL_AUTHENTICATION_INTERFACE_VERSION,
+ "client_ed25519",
+ auth,
+ compute_password_digest,
+ digest_to_binary
+};
+
+static int init(void *p __attribute__((unused)))
+{
+ loaded= 1;
+ return 0;
+}
+
+static int deinit(void *p __attribute__((unused)))
+{
+ loaded= 0;
+ return 0;
+}
+
+maria_declare_plugin(ed25519)
+{
+ MYSQL_AUTHENTICATION_PLUGIN,
+ &info,
+ "ed25519",
+ "Sergei Golubchik",
+ "Elliptic curve ED25519 based authentication",
+ PLUGIN_LICENSE_GPL,
+ init,
+ deinit,
+ 0x0101,
+ NULL,
+ NULL,
+ "1.1",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
+
+/************************** UDF ****************************************/
+MYSQL_PLUGIN_EXPORT
+char *ed25519_password(UDF_INIT *initid __attribute__((unused)),
+ UDF_ARGS *args, char *result, unsigned long *length,
+ char *is_null, char *error __attribute__((unused)))
+{
+ unsigned char pk[CRYPTO_PUBLICKEYBYTES];
+
+ if ((*is_null= !args->args[0]))
+ return NULL;
+
+ *length= PASSWORD_LEN;
+ crypto_sign_keypair(pk, (unsigned char*)args->args[0], args->lengths[0]);
+ my_base64_encode(pk, CRYPTO_PUBLICKEYBYTES, result);
+ return result;
+}
+
+/*
+ At least one of _init/_deinit is needed unless the server is started
+ with --allow_suspicious_udfs.
+*/
+MYSQL_PLUGIN_EXPORT
+my_bool ed25519_password_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
+{
+ if (args->arg_count != 1 || args->arg_type[0] != STRING_RESULT)
+ {
+ strcpy(message,"Wrong arguments to ed25519_password()");
+ return 1;
+ }
+ if (!loaded)
+ {
+ /* cannot work unless the plugin is loaded, we need services. */
+ strcpy(message,"Authentication plugin ed25519 is not loaded");
+ return 1;
+ }
+ initid->max_length= PASSWORD_LEN_BUF;
+ return 0;
+}
diff --git a/plugin/auth_examples/CMakeLists.txt b/plugin/auth_examples/CMakeLists.txt
new file mode 100644
index 00000000..0efd8348
--- /dev/null
+++ b/plugin/auth_examples/CMakeLists.txt
@@ -0,0 +1,36 @@
+# Copyright (c) 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 the Free Software Foundation; version 2 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
+
+MYSQL_ADD_PLUGIN(dialog_examples dialog_examples.c
+ MODULE_ONLY COMPONENT Test)
+MYSQL_ADD_PLUGIN(auth_test_plugin test_plugin.c
+ MODULE_ONLY COMPONENT Test)
+MYSQL_ADD_PLUGIN(qa_auth_interface qa_auth_interface.c
+ MODULE_ONLY COMPONENT Test)
+
+MYSQL_ADD_PLUGIN(qa_auth_server qa_auth_server.c
+ MODULE_ONLY COMPONENT Test)
+
+MYSQL_ADD_PLUGIN(qa_auth_client qa_auth_client.c
+ MODULE_ONLY COMPONENT Test)
+
+MYSQL_ADD_PLUGIN(auth_0x0100 auth_0x0100.c MODULE_ONLY COMPONENT Test)
+
+# disabled in favor of
+# libmariadb/plugins/auth/mariadb_cleartext.c
+#
+#MYSQL_ADD_PLUGIN(mysql_clear_password clear_password_client.c
+# MODULE_ONLY CLIENT COMPONENT ClientPlugins)
diff --git a/plugin/auth_examples/auth_0x0100.c b/plugin/auth_examples/auth_0x0100.c
new file mode 100644
index 00000000..e23f495f
--- /dev/null
+++ b/plugin/auth_examples/auth_0x0100.c
@@ -0,0 +1,91 @@
+/* Copyright (C) 2013 Sergei Golubchik and Monty Program Ab
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; version 2 of the
+ License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/**
+ @file
+
+ auth plugin that uses old structures as of
+ MYSQL_AUTHENTICATION_INTERFACE_VERSION 0x0100
+
+ To test the old version support.
+ It intentionally uses no constants like CR_OK ok PASSWORD_USED_YES.
+*/
+
+#include <mysql/plugin.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#if 0
+#include <mysql/plugin_auth.h>
+#else
+#define MYSQL_AUTHENTICATION_INTERFACE_VERSION 0x0100
+typedef void MYSQL_PLUGIN_VIO; /* we don't use it here */
+
+typedef struct st_mysql_server_auth_info
+{
+ char *user_name;
+ unsigned int user_name_length;
+ const char *auth_string;
+ unsigned long auth_string_length;
+ char authenticated_as[49];
+ char external_user[512];
+ int password_used;
+ const char *host_or_ip;
+ unsigned int host_or_ip_length;
+} MYSQL_SERVER_AUTH_INFO;
+
+struct st_mysql_auth
+{
+ int interface_version;
+ const char *client_auth_plugin;
+ int (*authenticate_user)(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info);
+};
+#endif
+
+static int do_auth_0x0100(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
+{
+ info->password_used= 1;
+ strcpy(info->authenticated_as, "zzzzzzzzzzzzzzzz");
+ memset(info->external_user, 'o', 510);
+ info->external_user[510]='.';
+ info->external_user[511]=0;
+ return vio ? -1 : 0; /* use vio to avoid the 'unused' warning */
+}
+
+static struct st_mysql_auth auth_0x0100_struct=
+{
+ MYSQL_AUTHENTICATION_INTERFACE_VERSION, 0, do_auth_0x0100
+};
+
+maria_declare_plugin(auth_0x0100)
+{
+ MYSQL_AUTHENTICATION_PLUGIN,
+ &auth_0x0100_struct,
+ "auth_0x0100",
+ "Sergei Golubchik",
+ "Test for API 0x0100 support",
+ PLUGIN_LICENSE_GPL,
+ NULL,
+ NULL,
+ 0x0100,
+ NULL,
+ NULL,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_EXPERIMENTAL,
+}
+maria_declare_plugin_end;
+
diff --git a/plugin/auth_examples/clear_password_client.c b/plugin/auth_examples/clear_password_client.c
new file mode 100644
index 00000000..726d200d
--- /dev/null
+++ b/plugin/auth_examples/clear_password_client.c
@@ -0,0 +1,47 @@
+/* Copyright (c) 2000, 2011, 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
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include <mysql/client_plugin.h>
+#include <mysql.h>
+#include <string.h>
+
+/**
+ The main function of the mysql_clear_password authentication plugin.
+*/
+
+static int clear_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
+{
+ int res;
+
+ /* send password in clear text */
+ res= vio->write_packet(vio, (const unsigned char *) mysql->passwd,
+ strlen(mysql->passwd) + 1);
+
+ return res ? CR_ERROR : CR_OK;
+}
+
+mysql_declare_client_plugin(AUTHENTICATION)
+ "mysql_clear_password",
+ "Georgi Kodinov",
+ "Clear password authentication plugin",
+ {0,1,0},
+ "GPL",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ clear_password_auth_client
+mysql_end_client_plugin;
+
diff --git a/plugin/auth_examples/dialog_examples.c b/plugin/auth_examples/dialog_examples.c
new file mode 100644
index 00000000..834c028c
--- /dev/null
+++ b/plugin/auth_examples/dialog_examples.c
@@ -0,0 +1,158 @@
+/* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab
+ Copyright (c) 2010, 2011, Oracle and/or its affiliates.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; version 2 of the
+ License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/**
+ @file
+
+ examples for dialog client authentication plugin
+
+ Two examples are provided: two_questions server plugin, that asks
+ the password and an "Are you sure?" question with a reply "yes, of course".
+ It demonstrates the usage of "password" (input is hidden) and "ordinary"
+ (input can be echoed) questions, and how to mark the last question,
+ to avoid an extra roundtrip.
+
+ And three_attempts plugin that gives the user three attempts to enter
+ a correct password. It shows the situation when a number of questions
+ is not known in advance.
+*/
+
+#include <mysql/plugin_auth.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <mysql/auth_dialog_client.h>
+
+/********************* SERVER SIDE ****************************************/
+
+/**
+ dialog demo with two questions, one password and one, the last, ordinary.
+*/
+static int two_questions(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
+{
+ unsigned char *pkt;
+ int pkt_len;
+
+ /* send a password question */
+ if (vio->write_packet(vio,
+ (const unsigned char *) PASSWORD_QUESTION "Password, please:",
+ 18))
+ return CR_ERROR;
+
+ /* read the answer */
+ if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
+ return CR_ERROR;
+
+ info->password_used= PASSWORD_USED_YES;
+
+ /* fail if the password is wrong */
+ if (strcmp((const char *) pkt, info->auth_string))
+ return CR_ERROR;
+
+ /* send the last, ordinary, question */
+ if (vio->write_packet(vio,
+ (const unsigned char *) LAST_QUESTION "Are you sure ?",
+ 15))
+ return CR_ERROR;
+
+ /* read the answer */
+ if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
+ return CR_ERROR;
+
+ /* check the reply */
+ return strcmp((const char *) pkt, "yes, of course") ? CR_ERROR : CR_OK;
+}
+
+static struct st_mysql_auth two_handler=
+{
+ MYSQL_AUTHENTICATION_INTERFACE_VERSION,
+ "dialog", /* requires dialog client plugin */
+ two_questions,
+ NULL, NULL /* no PASSWORD() */
+};
+
+/* dialog demo where the number of questions is not known in advance */
+static int three_attempts(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
+{
+ unsigned char *pkt;
+ int pkt_len, i;
+
+ for (i= 0; i < 3; i++)
+ {
+ /* send the prompt */
+ if (vio->write_packet(vio,
+ (const unsigned char *) PASSWORD_QUESTION "Password, please:", 18))
+ return CR_ERROR;
+
+ /* read the password */
+ if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
+ return CR_ERROR;
+
+ info->password_used= PASSWORD_USED_YES;
+
+ /*
+ finish, if the password is correct.
+ note, that we did not mark the prompt packet as "last"
+ */
+ if (strcmp((const char *) pkt, info->auth_string) == 0)
+ return CR_OK;
+ }
+
+ return CR_ERROR;
+}
+
+static struct st_mysql_auth three_handler=
+{
+ MYSQL_AUTHENTICATION_INTERFACE_VERSION,
+ "dialog", /* requires dialog client plugin */
+ three_attempts,
+ NULL, NULL /* no PASSWORD() */
+};
+
+mysql_declare_plugin(dialog)
+{
+ MYSQL_AUTHENTICATION_PLUGIN,
+ &two_handler,
+ "two_questions",
+ "Sergei Golubchik",
+ "Dialog plugin demo 1",
+ PLUGIN_LICENSE_GPL,
+ NULL,
+ NULL,
+ 0x0100,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+},
+{
+ MYSQL_AUTHENTICATION_PLUGIN,
+ &three_handler,
+ "three_attempts",
+ "Sergei Golubchik",
+ "Dialog plugin demo 2",
+ PLUGIN_LICENSE_GPL,
+ NULL,
+ NULL,
+ 0x0100,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+}
+mysql_declare_plugin_end;
+
diff --git a/plugin/auth_examples/qa_auth_client.c b/plugin/auth_examples/qa_auth_client.c
new file mode 100644
index 00000000..a915306e
--- /dev/null
+++ b/plugin/auth_examples/qa_auth_client.c
@@ -0,0 +1,117 @@
+/* Copyright (c) 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 the Free Software Foundation; version 2 of the
+ License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include <my_global.h>
+#include <mysql/plugin_auth.h>
+#include <mysql/client_plugin.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/********************* CLIENT SIDE ***************************************/
+/*
+ client plugin used for testing the plugin API
+*/
+#include <mysql.h>
+
+/**
+ The main function of the test plugin.
+
+ Reads the prompt, check if the handshake is done and if the prompt is a
+ password request and returns the password. Otherwise return error.
+
+ @note
+ 1. this plugin shows how a client authentication plugin
+ may read a MySQL protocol OK packet internally - which is important
+ where a number of packets is not known in advance.
+ 2. the first byte of the prompt is special. it is not
+ shown to the user, but signals whether it is the last question
+ (prompt[0] & 1 == 1) or not last (prompt[0] & 1 == 0),
+ and whether the input is a password (not echoed).
+ 3. the prompt is expected to be sent zero-terminated
+*/
+static int test_plugin_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
+{
+ unsigned char *pkt, cmd= 0;
+ int pkt_len, res;
+ char *reply;
+
+ do
+ {
+ /* read the prompt */
+ pkt_len= vio->read_packet(vio, &pkt);
+ if (pkt_len < 0)
+ return CR_ERROR;
+
+ if (pkt == 0)
+ {
+ /*
+ in mysql_change_user() the client sends the first packet, so
+ the first vio->read_packet() does nothing (pkt == 0).
+
+ We send the "password", assuming the client knows what its doing.
+ (in other words, the dialog plugin should be only set as a default
+ authentication plugin on the client if the first question
+ asks for a password - which will be sent in cleat text, by the way)
+ */
+ reply= mysql->passwd;
+ }
+ else
+ {
+ cmd= *pkt++;
+
+ /* is it MySQL protocol (0=OK or 254=need old password) packet ? */
+ if (cmd == 0 || cmd == 254)
+ return CR_OK_HANDSHAKE_COMPLETE; /* yes. we're done */
+
+ /*
+ asking for a password with an empty prompt means mysql->password
+ otherwise return an error
+ */
+ if ((cmd == LAST_PASSWORD[0] || cmd == PASSWORD_QUESTION[0]) && *pkt == 0)
+ reply= mysql->passwd;
+ else
+ return CR_ERROR;
+ }
+ if (!reply)
+ return CR_ERROR;
+ /* send the reply to the server */
+ res= vio->write_packet(vio, (const unsigned char *) reply,
+ (int)strlen(reply) + 1);
+
+ if (res)
+ return CR_ERROR;
+
+ /* repeat unless it was the last question */
+ } while (cmd != LAST_QUESTION[0] && cmd != PASSWORD_QUESTION[0]);
+
+ /* the job of reading the ok/error packet is left to the server */
+ return CR_OK;
+}
+
+
+mysql_declare_client_plugin(AUTHENTICATION)
+ "qa_auth_client",
+ "Horst Hunger",
+ "Dialog Client Authentication Plugin",
+ {0,1,0},
+ "GPL",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ test_plugin_client
+mysql_end_client_plugin;
diff --git a/plugin/auth_examples/qa_auth_interface.c b/plugin/auth_examples/qa_auth_interface.c
new file mode 100644
index 00000000..ad1f6fff
--- /dev/null
+++ b/plugin/auth_examples/qa_auth_interface.c
@@ -0,0 +1,254 @@
+/* Copyright (c) 2010, 2011, 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 the Free Software Foundation; version 2 of the
+ License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include <my_global.h>
+#include <mysql/plugin_auth.h>
+#include <mysql/client_plugin.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/********************* SERVER SIDE ****************************************/
+
+static int qa_auth_interface (MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
+{
+ unsigned char *pkt;
+ int pkt_len, err= CR_OK;
+
+ /* send a password question */
+ if (vio->write_packet(vio, (const unsigned char *) PASSWORD_QUESTION, 1))
+ return CR_ERROR;
+
+ /* read the answer */
+ if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
+ return CR_ERROR;
+
+ info->password_used= PASSWORD_USED_YES;
+
+ /* fail if the password is wrong */
+ if (strcmp((const char *) pkt, info->auth_string))
+ return CR_ERROR;
+
+/* Check the contens of components of info */
+ if (strcmp(info->user_name, "qa_test_1_user")== 0)
+ {
+ if (info->user_name_length != 14)
+ err= CR_ERROR;
+ if (strcmp(info->auth_string, "qa_test_1_dest"))
+ err= CR_ERROR;
+ if (info->auth_string_length != 14)
+ err= CR_ERROR;
+/* To be set by the plugin */
+/* if (strcmp(info->authenticated_as, "qa_test_1_user")) */
+/* err= CR_ERROR; */
+/* To be set by the plugin */
+/* if (strcmp(info->external_user, "")) */
+/* err= CR_ERROR; */
+ if (info->password_used != PASSWORD_USED_YES)
+ err= CR_ERROR;
+ if (strcmp(info->host_or_ip, "localhost"))
+ err= CR_ERROR;
+ if (info->host_or_ip_length != 9)
+ err= CR_ERROR;
+ }
+/* Assign values to the components of info even if not intended and watch the effect */
+ else if (strcmp(info->user_name, "qa_test_2_user")== 0)
+ {
+ /* Overwriting not intended, but with effect on USER() */
+ strcpy((char*) info->user_name, "user_name");
+ info->user_name_length= 9;
+ /* Overwriting not intended, effect not visible */
+ strcpy((char *)info->auth_string, "auth_string");
+ info->auth_string_length= 11;
+ /* Assign with account for authorization, effect on CURRENT_USER() */
+ strcpy(info->authenticated_as, "authenticated_as");
+ /* Assign with an external account, effect on @@local.EXTERNAL_USER */
+ strcpy(info->external_user, "externaluser");
+ /* Overwriting will cause a core dump */
+/* strcpy(info->host_or_ip, "host_or_ip"); */
+/* info->host_or_ip_length= 10; */
+ }
+/* Invalid, means too high values for length */
+ else if (strcmp(info->user_name, "qa_test_3_user")== 0)
+ {
+/* Original value is 14. Test runs also with higher value. Changes have no effect.*/
+ info->user_name_length= 28;
+ strcpy((char *)info->auth_string, "qa_test_3_dest");
+/* Original value is 14. Test runs also with higher value. Changes have no effect.*/
+ info->auth_string_length= 28;
+ strcpy(info->authenticated_as, info->auth_string);
+ strcpy(info->external_user, info->auth_string);
+ }
+/* Invalid, means too low values for length */
+ else if (strcmp(info->user_name, "qa_test_4_user")== 0)
+ {
+/* Original value is 14. Test runs also with lower value. Changes have no effect.*/
+ info->user_name_length= 8;
+ strcpy((char *)info->auth_string, "qa_test_4_dest");
+/* Original value is 14. Test runs also with lower value. Changes have no effect.*/
+ info->auth_string_length= 8;
+ strcpy(info->authenticated_as, info->auth_string);
+ strcpy(info->external_user, info->auth_string);
+ }
+/* Overwrite with empty values */
+ else if (strcmp(info->user_name, "qa_test_5_user")== 0)
+ {
+/* This assignment has no effect.*/
+ strcpy((char*) info->user_name, "");
+ info->user_name_length= 0;
+/* This assignment has no effect.*/
+ strcpy((char *)info->auth_string, "");
+ info->auth_string_length= 0;
+/* This assignment caused an error or an "empty" user */
+ strcpy(info->authenticated_as, "");
+/* This assignment has no effect.*/
+ strcpy(info->external_user, "");
+ /* Overwriting will cause a core dump */
+/* strcpy(info->host_or_ip, ""); */
+/* info->host_or_ip_length= 0; */
+ }
+/* Set to 'root' */
+ else if (strcmp(info->user_name, "qa_test_6_user")== 0)
+ {
+ strcpy(info->authenticated_as, "root");
+ }
+ else
+ {
+ err= CR_ERROR;
+ }
+ return err;
+}
+
+static struct st_mysql_auth qa_auth_test_handler=
+{
+ MYSQL_AUTHENTICATION_INTERFACE_VERSION,
+ "qa_auth_interface", /* requires test_plugin client's plugin */
+ qa_auth_interface,
+ NULL, NULL /* no PASSWORD() */
+};
+
+mysql_declare_plugin(test_plugin)
+{
+ MYSQL_AUTHENTICATION_PLUGIN,
+ &qa_auth_test_handler,
+ "qa_auth_interface",
+ "Horst Hunger",
+ "plugin API test plugin",
+ PLUGIN_LICENSE_GPL,
+ NULL,
+ NULL,
+ 0x0100,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+}
+mysql_declare_plugin_end;
+
+/********************* CLIENT SIDE ***************************************/
+/*
+ client plugin used for testing the plugin API
+*/
+#include <mysql.h>
+
+/**
+ The main function of the test plugin.
+
+ Reads the prompt, check if the handshake is done and if the prompt is a
+ password request and returns the password. Otherwise return error.
+
+ @note
+ 1. this plugin shows how a client authentication plugin
+ may read a MySQL protocol OK packet internally - which is important
+ where a number of packets is not known in advance.
+ 2. the first byte of the prompt is special. it is not
+ shown to the user, but signals whether it is the last question
+ (prompt[0] & 1 == 1) or not last (prompt[0] & 1 == 0),
+ and whether the input is a password (not echoed).
+ 3. the prompt is expected to be sent zero-terminated
+*/
+static int test_plugin_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
+{
+ unsigned char *pkt, cmd= 0;
+ int pkt_len, res;
+ char *reply;
+
+ do
+ {
+ /* read the prompt */
+ pkt_len= vio->read_packet(vio, &pkt);
+ if (pkt_len < 0)
+ return CR_ERROR;
+
+ if (pkt == 0)
+ {
+ /*
+ in mysql_change_user() the client sends the first packet, so
+ the first vio->read_packet() does nothing (pkt == 0).
+
+ We send the "password", assuming the client knows what its doing.
+ (in other words, the dialog plugin should be only set as a default
+ authentication plugin on the client if the first question
+ asks for a password - which will be sent in cleat text, by the way)
+ */
+ reply= mysql->passwd;
+ }
+ else
+ {
+ cmd= *pkt++;
+
+ /* is it MySQL protocol (0=OK or 254=need old password) packet ? */
+ if (cmd == 0 || cmd == 254)
+ return CR_OK_HANDSHAKE_COMPLETE; /* yes. we're done */
+
+ /*
+ asking for a password with an empty prompt means mysql->password
+ otherwise return an error
+ */
+ if ((cmd == LAST_PASSWORD[0] || cmd == PASSWORD_QUESTION[0]) && *pkt == 0)
+ reply= mysql->passwd;
+ else
+ return CR_ERROR;
+ }
+ if (!reply)
+ return CR_ERROR;
+ /* send the reply to the server */
+ res= vio->write_packet(vio, (const unsigned char *) reply,
+ (int)strlen(reply) + 1);
+
+ if (res)
+ return CR_ERROR;
+
+ /* repeat unless it was the last question */
+ } while (cmd != LAST_QUESTION[0] && cmd != PASSWORD_QUESTION[0]);
+
+ /* the job of reading the ok/error packet is left to the server */
+ return CR_OK;
+}
+
+
+mysql_declare_client_plugin(AUTHENTICATION)
+ "qa_auth_interface",
+ "Horst Hunger",
+ "Dialog Client Authentication Plugin",
+ {0,1,0},
+ "GPL",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ test_plugin_client
+mysql_end_client_plugin;
diff --git a/plugin/auth_examples/qa_auth_server.c b/plugin/auth_examples/qa_auth_server.c
new file mode 100644
index 00000000..67b29d26
--- /dev/null
+++ b/plugin/auth_examples/qa_auth_server.c
@@ -0,0 +1,79 @@
+/* Copyright (c) 2010, 2011, 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 the Free Software Foundation; version 2 of the
+ License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include <my_global.h>
+#include <mysql/plugin_auth.h>
+#include <mysql/client_plugin.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/********************* SERVER SIDE ****************************************/
+
+static int qa_auth_interface (MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
+{
+ unsigned char *pkt;
+ int pkt_len, err= CR_OK;
+
+ /* send a password question */
+ if (vio->write_packet(vio, (const unsigned char *) PASSWORD_QUESTION, 1))
+ return CR_ERROR;
+
+ /* read the answer */
+ if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
+ return CR_ERROR;
+
+ info->password_used= PASSWORD_USED_YES;
+
+ /* fail if the password is wrong */
+ if (strcmp((const char *) pkt, info->auth_string))
+ return CR_ERROR;
+
+/* Test of default_auth */
+ if (strcmp(info->user_name, "qa_test_11_user")== 0)
+ {
+ strcpy(info->authenticated_as, "qa_test_11_dest");
+ }
+ else
+ err= CR_ERROR;
+ return err;
+}
+
+static struct st_mysql_auth qa_auth_test_handler=
+{
+ MYSQL_AUTHENTICATION_INTERFACE_VERSION,
+ "qa_auth_interface", /* requires test_plugin client's plugin */
+ qa_auth_interface,
+ NULL, NULL /* no PASSWORD() */
+};
+
+mysql_declare_plugin(test_plugin)
+{
+ MYSQL_AUTHENTICATION_PLUGIN,
+ &qa_auth_test_handler,
+ "qa_auth_server",
+ "Horst Hunger",
+ "plugin API test plugin",
+ PLUGIN_LICENSE_GPL,
+ NULL,
+ NULL,
+ 0x0100,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+}
+mysql_declare_plugin_end;
diff --git a/plugin/auth_examples/test_plugin.c b/plugin/auth_examples/test_plugin.c
new file mode 100644
index 00000000..04405a1c
--- /dev/null
+++ b/plugin/auth_examples/test_plugin.c
@@ -0,0 +1,234 @@
+/* Copyright (c) 2010, 2011, 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 the Free Software Foundation; version 2 of the
+ License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/**
+ @file
+
+ Test driver for the mysql-test/t/plugin_auth.test
+
+ This is a set of test plugins used to test the external authentication
+ implementation.
+ See the above test file for more details.
+ This test plugin is based on the dialog plugin example.
+*/
+
+#include <my_global.h>
+#include <mysql/plugin_auth.h>
+#include <mysql/client_plugin.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/********************* SERVER SIDE ****************************************/
+
+/**
+ dialog test plugin mimicking the ordinary auth mechanism. Used to test the auth plugin API
+*/
+static int auth_test_plugin(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
+{
+ unsigned char *pkt;
+ int pkt_len;
+
+ /* send a password question */
+ if (vio->write_packet(vio, (const unsigned char *) PASSWORD_QUESTION, 1))
+ return CR_ERROR;
+
+ /* read the answer */
+ if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
+ return CR_ERROR;
+
+ info->password_used= PASSWORD_USED_YES;
+
+ /* fail if the password is wrong */
+ if (strcmp((const char *) pkt, info->auth_string))
+ return CR_ERROR;
+
+ /* copy auth string as a destination name to check it */
+ strcpy (info->authenticated_as, info->auth_string);
+
+ /* copy something into the external user name */
+ strcpy (info->external_user, info->auth_string);
+
+ return CR_OK;
+}
+
+static struct st_mysql_auth auth_test_handler=
+{
+ MYSQL_AUTHENTICATION_INTERFACE_VERSION,
+ "auth_test_plugin", /* requires test_plugin client's plugin */
+ auth_test_plugin,
+ NULL, NULL /* no PASSWORD() */
+};
+
+/**
+ dialog test plugin mimicking the ordinary auth mechanism. Used to test the clear text plugin API
+*/
+static int auth_cleartext_plugin(MYSQL_PLUGIN_VIO *vio,
+ MYSQL_SERVER_AUTH_INFO *info)
+{
+ unsigned char *pkt;
+ int pkt_len;
+
+ /* read the password */
+ if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
+ return CR_ERROR;
+
+ info->password_used= PASSWORD_USED_YES;
+
+ /* fail if the password is wrong */
+ if (strcmp((const char *) pkt, info->auth_string))
+ return CR_ERROR;
+
+ return CR_OK;
+}
+
+
+static struct st_mysql_auth auth_cleartext_handler=
+{
+ MYSQL_AUTHENTICATION_INTERFACE_VERSION,
+ "mysql_clear_password", /* requires the clear text plugin */
+ auth_cleartext_plugin,
+ NULL, NULL /* no PASSWORD() */
+};
+
+mysql_declare_plugin(test_plugin)
+{
+ MYSQL_AUTHENTICATION_PLUGIN,
+ &auth_test_handler,
+ "test_plugin_server",
+ "Georgi Kodinov",
+ "plugin API test plugin",
+ PLUGIN_LICENSE_GPL,
+ NULL,
+ NULL,
+ 0x0100,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+},
+{
+ MYSQL_AUTHENTICATION_PLUGIN,
+ &auth_cleartext_handler,
+ "cleartext_plugin_server",
+ "Georgi Kodinov",
+ "cleartext plugin API test plugin",
+ PLUGIN_LICENSE_GPL,
+ NULL,
+ NULL,
+ 0x0100,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+}
+mysql_declare_plugin_end;
+
+
+/********************* CLIENT SIDE ***************************************/
+/*
+ client plugin used for testing the plugin API
+*/
+#include <mysql.h>
+
+/**
+ The main function of the test plugin.
+
+ Reads the prompt, check if the handshake is done and if the prompt is a
+ password request and returns the password. Otherwise return error.
+
+ @note
+ 1. this plugin shows how a client authentication plugin
+ may read a MySQL protocol OK packet internally - which is important
+ where a number of packets is not known in advance.
+ 2. the first byte of the prompt is special. it is not
+ shown to the user, but signals whether it is the last question
+ (prompt[0] & 1 == 1) or not last (prompt[0] & 1 == 0),
+ and whether the input is a password (not echoed).
+ 3. the prompt is expected to be sent zero-terminated
+*/
+static int test_plugin_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
+{
+ unsigned char *pkt, cmd= 0;
+ int pkt_len, res;
+ char *reply;
+
+ do
+ {
+ /* read the prompt */
+ pkt_len= vio->read_packet(vio, &pkt);
+ if (pkt_len < 0)
+ return CR_ERROR;
+
+ if (pkt == 0)
+ {
+ /*
+ in mysql_change_user() the client sends the first packet, so
+ the first vio->read_packet() does nothing (pkt == 0).
+
+ We send the "password", assuming the client knows what it's doing.
+ (in other words, the dialog plugin should be only set as a default
+ authentication plugin on the client if the first question
+ asks for a password - which will be sent in clear text, by the way)
+ */
+ reply= mysql->passwd;
+ }
+ else
+ {
+ cmd= *pkt++;
+
+ /* is it MySQL protocol (0=OK or 254=need old password) packet ? */
+ if (cmd == 0 || cmd == 254)
+ return CR_OK_HANDSHAKE_COMPLETE; /* yes. we're done */
+
+ /*
+ asking for a password with an empty prompt means mysql->password
+ otherwise return an error
+ */
+ if ((cmd == LAST_PASSWORD[0] || cmd == PASSWORD_QUESTION[0]) && *pkt == 0)
+ reply= mysql->passwd;
+ else
+ return CR_ERROR;
+ }
+ if (!reply)
+ return CR_ERROR;
+ /* send the reply to the server */
+ res= vio->write_packet(vio, (const unsigned char *) reply,
+ (int)strlen(reply) + 1);
+
+ if (res)
+ return CR_ERROR;
+
+ /* repeat unless it was the last question */
+ } while (cmd != LAST_QUESTION[0] && cmd != PASSWORD_QUESTION[0]);
+
+ /* the job of reading the ok/error packet is left to the server */
+ return CR_OK;
+}
+
+
+mysql_declare_client_plugin(AUTHENTICATION)
+ "auth_test_plugin",
+ "Georgi Kodinov",
+ "Dialog Client Authentication Plugin",
+ {0,1,0},
+ "GPL",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ test_plugin_client
+mysql_end_client_plugin;
diff --git a/plugin/auth_gssapi/CMakeLists.txt b/plugin/auth_gssapi/CMakeLists.txt
new file mode 100644
index 00000000..7fc0819a
--- /dev/null
+++ b/plugin/auth_gssapi/CMakeLists.txt
@@ -0,0 +1,54 @@
+IF (WIN32)
+ SET(USE_SSPI 1)
+ENDIF()
+
+IF(USE_SSPI)
+ SET(GSSAPI_LIBS secur32)
+ ADD_DEFINITIONS(-DPLUGIN_SSPI)
+ SET(GSSAPI_CLIENT sspi_client.cc)
+ SET(GSSAPI_SERVER sspi_server.cc)
+ SET(GSSAPI_ERRMSG sspi_errmsg.cc)
+ELSE()
+ SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
+ FIND_PACKAGE(GSSAPI)
+ SET_PACKAGE_PROPERTIES(GSSAPI PROPERTIES TYPE OPTIONAL)
+ IF(GSSAPI_FOUND)
+ INCLUDE_DIRECTORIES(${GSSAPI_INCS})
+ ADD_DEFINITIONS(-DPLUGIN_GSSAPI)
+ SET(GSSAPI_CLIENT gssapi_client.cc)
+ SET(GSSAPI_SERVER gssapi_server.cc)
+ SET(GSSAPI_ERRMSG gssapi_errmsg.cc)
+
+ IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ SET_SOURCE_FILES_PROPERTIES(
+ ${GSSAPI_CLIENT} ${GSSAPI_SERVER} ${GSSAPI_ERRMSG}
+ PROPERTY COMPILE_FLAGS "-Wno-deprecated-declarations")
+ ENDIF()
+ SET(CMAKE_REQUIRED_INCLUDES ${GSSAPI_INCS})
+ SET(CMAKE_REQUIRED_LIBRARIES ${GSSAPI_LIBS})
+ SET(CMAKE_REQUIRED_FLAGS "-Werror -Wall")
+ INCLUDE(CheckCXXSymbolExists)
+ CHECK_CXX_SYMBOL_EXISTS(krb5_xfree "krb5.h" HAVE_KRB5_XFREE)
+ IF(HAVE_KRB5_XFREE)
+ ADD_DEFINITIONS(-DHAVE_KRB5_XFREE=1)
+ ENDIF()
+
+ ELSE()
+ # Can't build plugin
+ RETURN()
+ ENDIF()
+ENDIF ()
+
+
+MYSQL_ADD_PLUGIN(auth_gssapi server_plugin.cc ${GSSAPI_SERVER} ${GSSAPI_ERRMSG}
+ LINK_LIBRARIES ${GSSAPI_LIBS}
+ COMPONENT gssapi-server
+ MODULE_ONLY)
+
+# disabled in favor of libmariadb/plugins/auth/auth_gssapi_client.c
+#
+#MYSQL_ADD_PLUGIN(auth_gssapi_client client_plugin.cc ${GSSAPI_CLIENT} ${GSSAPI_ERRMSG}
+# LINK_LIBRARIES ${GSSAPI_LIBS COMPONENT ClientPlugins}
+# COMPONENT gssapi-client
+# CLIENT
+# MODULE_ONLY)
diff --git a/plugin/auth_gssapi/README.md b/plugin/auth_gssapi/README.md
new file mode 100644
index 00000000..ea8deaaf
--- /dev/null
+++ b/plugin/auth_gssapi/README.md
@@ -0,0 +1,129 @@
+# GSSAPI/SSPI authentication for MariaDB
+
+This article gives instructions on configuring GSSAPI authentication plugin
+for MariaDB for passwordless login.
+
+On Unix systems, GSSAPI is usually synonymous with Kerberos authentication.
+Windows has slightly different but very similar API called SSPI, that along with Kerberos, also supports NTLM authentication.
+
+This plugin includes support for Kerberos on Unix, but also can be used as for Windows authentication with or without domain
+environment.
+
+## Server-side preparations on Unix
+To use the plugin, some preparation need to be done on the server side on Unixes.
+MariaDB server will need read access to the Kerberos keytab file, that contains service principal name for the MariaDB server.
+
+
+If you are using **Unix Kerberos KDC (MIT,Heimdal)**
+
+- Create service principal using kadmin tool
+
+```
+kadmin -q "addprinc -randkey mariadb/host.domain.com"
+```
+
+(replace host.domain.com with fully qualified DNS name for the server host)
+
+- Export the newly created user to the keytab file
+
+```
+kadmin -q "ktadd -k /path/to/mariadb.keytab mariadb/host.domain.com"
+```
+
+More details can be found [here](http://www.microhowto.info/howto/create_a_service_principal_using_mit_kerberos.html)
+and [here](http://www.microhowto.info/howto/add_a_host_or_service_principal_to_a_keytab_using_mit_kerberos.html)
+
+If you are using **Windows Active Directory KDC**
+you can need to create keytab using ktpass.exe tool on Windows, map principal user to an existing domain user like this
+
+```
+ktpass.exe /princ mariadb/host.domain.com@DOMAIN.COM /mapuser someuser /pass MyPas$w0rd /out mariadb.keytab /crypto all /ptype KRB5_NT_PRINCIPAL /mapop set
+```
+
+and then transfer the keytab file to the Unix server. See [Microsoft documentation](https://technet.microsoft.com/en-us/library/cc753771.aspx) for details.
+
+
+## Server side preparations on Windows.
+Usually nothing need to be done. MariaDB server should to run on a domain joined machine, either as NetworkService account
+(which is default if it runs as service) or run under any other domain account credentials.
+Creating service principal is not required here (but you can still do it using [_setspn_](https://technet.microsoft.com/en-us/library/cc731241.aspx) tool)
+
+
+# Installing plugin
+- Start the server
+
+- On Unix, edit my the my.cnf/my.ini configuration file, set the parameter gssapi-keytab-path to point to previously
+created keytab path.
+
+```
+ gssapi-keytab-path=/path/to/mariadb.keytab
+```
+
+- Optionally on Unix, in case the service principal name differs from default mariadb/host.domain.com@REALM,
+configure alternative principal name with
+
+```
+ gssapi-principal-name=alternative/principalname@REALM
+```
+
+- In mysql command line client, execute
+
+```
+ INSTALL SONAME 'auth_gssapi'
+```
+
+#Creating users
+
+Now, you can create a user for GSSAPI/SSPI authentication. CREATE USER command, for Kerberos user
+would be like this (*long* form, see below for short one)
+
+```
+CREATE USER usr1 IDENTIFIED WITH gssapi AS 'usr1@EXAMPLE.COM';
+```
+
+(replace with real username and realm)
+
+The part after AS is mechanism specific, and needs to be ``machine\\usr1`` for Windows users identified with NTLM.
+
+You may also use alternative *short* form of CREATE USER
+
+```
+CREATE USER usr1 IDENTIFIED WITH gssapi;
+```
+
+If this syntax is used, realm part is *not* used for comparison
+thus 'usr1@EXAMPLE.COM', 'usr1@EXAMPLE.CO.UK' and 'mymachine\usr1' will all identify as 'usr1'.
+
+#Login as GSSAPI user with command line clients
+
+Using command line client, do
+
+```
+mysql --plugin-dir=/path/to/plugin-dir -u usr1
+```
+
+#Plugin variables
+- **gssapi-keytab-path** (Unix only) - Path to the server keytab file
+- **gssapi-principal-name** - name of the service principal.
+- **gssapi-mech-name** (Windows only) - Name of the SSPI package used by server. Can be either 'Kerberos' or 'Negotiate'.
+ Defaults to 'Negotiate' (both Kerberos and NTLM users can connect)
+ Set it to 'Kerberos', to prevent less secure NTLM in domain environments, but leave it as default(Negotiate)
+ to allow non-domain environment (e.g if server does not run in domain environment).
+
+
+#Implementation
+
+Overview of the protocol between client and server
+
+1. Server : Construct gssapi-principal-name if not set in my.cnf. On Unixes defaults to hostbased name for service "mariadb". On Windows to user's or machine's domain names.
+Acquire credentials for gssapi-principal-name with ```gss_acquire_cred() / AcquireSecurityCredentials()```.
+Send packet with principal name and mech ```"gssapi-principal-name\0gssapi-mech-name\0"``` to client ( on Unix, empty string used for gssapi-mech)
+
+2. Client: execute ```gss_init_sec_context() / InitializeSecurityContext()``` passing gssapi-principal-name / gssapi-mech-name parameters.
+Send resulting GSSAPI blob to server.
+
+3. Server : receive blob from client, execute ```gss_accept_sec_context()/ AcceptSecurityContext()```, send resulting blob back to client
+
+4. Perform 2. and 3. can until both client and server decide that authentication is done, or until some error occurred. If authentication was successful, GSSAPI context (an opaque structure) is generated on both client and server sides.
+
+5. Server : Client name is extracted from the context, and compared to the name provided by client(with or without realm). If name matches, plugin returns success.
diff --git a/plugin/auth_gssapi/client_plugin.cc b/plugin/auth_gssapi/client_plugin.cc
new file mode 100644
index 00000000..0ab619a0
--- /dev/null
+++ b/plugin/auth_gssapi/client_plugin.cc
@@ -0,0 +1,112 @@
+/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood,
+Vladislav Vaintroub & MariaDB Corporation
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. 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.
+
+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 HOLDER 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.
+*/
+
+/**
+ @file
+
+ GSSAPI authentication plugin, client side
+*/
+#include <string.h>
+#include <stdarg.h>
+#include <mysqld_error.h>
+#include <mysql/client_plugin.h>
+#include <mysql.h>
+#include <stdio.h>
+#include "common.h"
+
+extern int auth_client(char *principal_name,
+ char *mech,
+ MYSQL *mysql,
+ MYSQL_PLUGIN_VIO *vio);
+
+static void parse_server_packet(char *packet, size_t packet_len, char *spn, char *mech)
+{
+ size_t spn_len;
+ spn_len = strnlen(packet, packet_len);
+ strncpy(spn, packet, PRINCIPAL_NAME_MAX);
+ if (spn_len == packet_len - 1)
+ {
+ /* Mechanism not included into packet */
+ *mech = 0;
+ }
+ else
+ {
+ strncpy(mech, packet + spn_len + 1, MECH_NAME_MAX);
+ }
+}
+
+/**
+ Set client error message.
+ */
+void log_client_error(MYSQL *mysql, const char *format, ...)
+{
+ NET *net= &mysql->net;
+ va_list args;
+
+ net->last_errno= ER_UNKNOWN_ERROR;
+ va_start(args, format);
+ vsnprintf(net->last_error, sizeof(net->last_error) - 1,
+ format, args);
+ va_end(args);
+ memcpy(net->sqlstate, "HY000", sizeof(net->sqlstate));
+}
+
+/**
+ The main client function of the GSSAPI plugin.
+ */
+static int gssapi_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
+{
+ int packet_len;
+ unsigned char *packet;
+ char spn[PRINCIPAL_NAME_MAX + 1];
+ char mech[MECH_NAME_MAX + 1];
+
+ /* read from server for service principal name */
+ packet_len= vio->read_packet(vio, &packet);
+ if (packet_len < 0)
+ {
+ return CR_ERROR;
+ }
+ parse_server_packet((char *)packet, (size_t)packet_len, spn, mech);
+ return auth_client(spn, mech, mysql, vio);
+}
+
+
+/* register client plugin */
+mysql_declare_client_plugin(AUTHENTICATION)
+ "auth_gssapi_client",
+ "Shuang Qiu, Robbie Harwood, Vladislav Vaintroub",
+ "GSSAPI/SSPI based authentication",
+ {0, 1, 0},
+ "BSD",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ gssapi_auth_client
+mysql_end_client_plugin;
diff --git a/plugin/auth_gssapi/cmake/FindGSSAPI.cmake b/plugin/auth_gssapi/cmake/FindGSSAPI.cmake
new file mode 100644
index 00000000..78d1ec84
--- /dev/null
+++ b/plugin/auth_gssapi/cmake/FindGSSAPI.cmake
@@ -0,0 +1,102 @@
+# - Try to detect the GSSAPI support
+# Once done this will define
+#
+# GSSAPI_FOUND - system supports GSSAPI
+# GSSAPI_INCS - the GSSAPI include directory
+# GSSAPI_LIBS - the libraries needed to use GSSAPI
+# GSSAPI_FLAVOR - the type of API - MIT or HEIMDAL
+
+# Copyright (c) 2006, Pino Toscano, <toscano.pino@tiscali.it>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+
+
+if(GSSAPI_LIBS AND GSSAPI_FLAVOR)
+
+ # in cache already
+ set(GSSAPI_FOUND TRUE)
+
+else(GSSAPI_LIBS AND GSSAPI_FLAVOR)
+
+ find_program(KRB5_CONFIG NAMES krb5-config heimdal-krb5-config PATHS
+ /opt/local/bin /usr/lib/mit/bin
+ ONLY_CMAKE_FIND_ROOT_PATH # this is required when cross compiling with cmake 2.6 and ignored with cmake 2.4, Alex
+ )
+ mark_as_advanced(KRB5_CONFIG)
+
+ #reset vars
+ set(GSSAPI_INCS)
+ set(GSSAPI_LIBS)
+ set(GSSAPI_FLAVOR)
+
+ if(KRB5_CONFIG)
+
+ set(HAVE_KRB5_GSSAPI TRUE)
+ exec_program(${KRB5_CONFIG} ARGS --libs gssapi RETURN_VALUE _return_VALUE OUTPUT_VARIABLE GSSAPI_LIBS)
+ if(_return_VALUE)
+ message(STATUS "GSSAPI configure check failed.")
+ set(HAVE_KRB5_GSSAPI FALSE)
+ endif(_return_VALUE)
+ IF(CMAKE_SYSTEM_NAME MATCHES AIX)
+ string(REGEX REPLACE "-Wl[A-Za-z0-9_/,:-]*[ $]?" "" GSSAPI_LIBS "${GSSAPI_LIBS}")
+ string(REGEX REPLACE "-L[A-Za-z0-9_/,:-]*[ $]?" "" GSSAPI_LIBS "${GSSAPI_LIBS}")
+ ENDIF()
+
+ exec_program(${KRB5_CONFIG} ARGS --cflags gssapi RETURN_VALUE _return_VALUE OUTPUT_VARIABLE GSSAPI_INCS)
+ string(REGEX REPLACE "(\r?\n)+$" "" GSSAPI_INCS "${GSSAPI_INCS}")
+ string(REGEX REPLACE " *-I" ";" GSSAPI_INCS "${GSSAPI_INCS}")
+
+ exec_program(${KRB5_CONFIG} ARGS --vendor RETURN_VALUE _return_VALUE OUTPUT_VARIABLE gssapi_flavor_tmp)
+ set(GSSAPI_FLAVOR_MIT)
+ if(gssapi_flavor_tmp MATCHES ".*Massachusetts.*")
+ set(GSSAPI_FLAVOR "MIT")
+ else(gssapi_flavor_tmp MATCHES ".*Massachusetts.*")
+ set(GSSAPI_FLAVOR "HEIMDAL")
+ endif(gssapi_flavor_tmp MATCHES ".*Massachusetts.*")
+
+ if(NOT HAVE_KRB5_GSSAPI)
+ if (gssapi_flavor_tmp MATCHES "Sun Microsystems.*")
+ message(STATUS "Solaris Kerberos does not have GSSAPI; this is normal.")
+ set(GSSAPI_LIBS)
+ set(GSSAPI_INCS)
+ else(gssapi_flavor_tmp MATCHES "Sun Microsystems.*")
+ message(WARNING "${KRB5_CONFIG} failed unexpectedly.")
+ endif(gssapi_flavor_tmp MATCHES "Sun Microsystems.*")
+ endif(NOT HAVE_KRB5_GSSAPI)
+
+ if(GSSAPI_LIBS) # GSSAPI_INCS can be also empty, so don't rely on that
+ set(GSSAPI_FOUND TRUE CACHE STRING "")
+ message(STATUS "Found GSSAPI: ${GSSAPI_LIBS}")
+
+ set(GSSAPI_INCS ${GSSAPI_INCS} CACHE STRING "")
+ set(GSSAPI_LIBS ${GSSAPI_LIBS} CACHE STRING "")
+ set(GSSAPI_FLAVOR ${GSSAPI_FLAVOR} CACHE STRING "")
+
+ mark_as_advanced(GSSAPI_INCS GSSAPI_LIBS GSSAPI_FLAVOR)
+
+ endif(GSSAPI_LIBS)
+
+ endif(KRB5_CONFIG)
+
+endif(GSSAPI_LIBS AND GSSAPI_FLAVOR)
diff --git a/plugin/auth_gssapi/common.h b/plugin/auth_gssapi/common.h
new file mode 100644
index 00000000..c04241ac
--- /dev/null
+++ b/plugin/auth_gssapi/common.h
@@ -0,0 +1,4 @@
+/** Maximal length of the target name */
+#define PRINCIPAL_NAME_MAX 256
+/** Maximal length of the mech string */
+#define MECH_NAME_MAX 30
diff --git a/plugin/auth_gssapi/gssapi_client.cc b/plugin/auth_gssapi/gssapi_client.cc
new file mode 100644
index 00000000..a05ea158
--- /dev/null
+++ b/plugin/auth_gssapi/gssapi_client.cc
@@ -0,0 +1,127 @@
+/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood,
+Vladislav Vaintroub & MariaDB Corporation
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. 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.
+
+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 HOLDER 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.
+*/
+
+#include <gssapi/gssapi.h>
+#include <string.h>
+#include <stdio.h>
+#include <mysql/plugin_auth.h>
+#include <mysqld_error.h>
+#include <mysql.h>
+#include "gssapi_errmsg.h"
+
+extern void log_client_error(MYSQL *mysql,const char *fmt,...);
+
+
+/* This sends the error to the client */
+static void log_error(MYSQL *mysql, OM_uint32 major, OM_uint32 minor, const char *msg)
+{
+ if (GSS_ERROR(major))
+ {
+ char sysmsg[1024];
+ gssapi_errmsg(major, minor, sysmsg, sizeof(sysmsg));
+ log_client_error(mysql,
+ "Client GSSAPI error (major %u, minor %u) : %s - %s",
+ major, minor, msg, sysmsg);
+ }
+ else
+ {
+ log_client_error(mysql, "Client GSSAPI error : %s", msg);
+ }
+}
+
+int auth_client(char *principal_name, char *mech, MYSQL *mysql, MYSQL_PLUGIN_VIO *vio)
+{
+
+ int ret= CR_ERROR;
+ OM_uint32 major= 0, minor= 0;
+ gss_ctx_id_t ctxt= GSS_C_NO_CONTEXT;
+ gss_name_t service_name= GSS_C_NO_NAME;
+
+ if (principal_name && principal_name[0])
+ {
+ /* import principal from plain text */
+ gss_buffer_desc principal_name_buf;
+ principal_name_buf.length= strlen(principal_name);
+ principal_name_buf.value= (void *) principal_name;
+ major= gss_import_name(&minor, &principal_name_buf, GSS_C_NT_USER_NAME, &service_name);
+ if (GSS_ERROR(major))
+ {
+ log_error(mysql, major, minor, "gss_import_name");
+ return CR_ERROR;
+ }
+ }
+
+ gss_buffer_desc input= {0,0};
+ do
+ {
+ gss_buffer_desc output= {0,0};
+ major= gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL, &ctxt, service_name,
+ GSS_C_NO_OID, 0, 0, GSS_C_NO_CHANNEL_BINDINGS,
+ &input, NULL, &output, NULL, NULL);
+ if (output.length)
+ {
+ /* send credential */
+ if(vio->write_packet(vio, (unsigned char *)output.value, output.length))
+ {
+ /* Server error packet contains detailed message. */
+ ret= CR_OK_HANDSHAKE_COMPLETE;
+ gss_release_buffer (&minor, &output);
+ goto cleanup;
+ }
+ }
+ gss_release_buffer (&minor, &output);
+
+ if (GSS_ERROR(major))
+ {
+ log_error(mysql, major, minor,"gss_init_sec_context");
+ goto cleanup;
+ }
+
+ if (major & GSS_S_CONTINUE_NEEDED)
+ {
+ int len= vio->read_packet(vio, (unsigned char **) &input.value);
+ if (len <= 0)
+ {
+ /* Server error packet contains detailed message. */
+ ret= CR_OK_HANDSHAKE_COMPLETE;
+ goto cleanup;
+ }
+ input.length= len;
+ }
+ } while (major & GSS_S_CONTINUE_NEEDED);
+
+ ret= CR_OK;
+
+cleanup:
+ if (service_name != GSS_C_NO_NAME)
+ gss_release_name(&minor, &service_name);
+ if (ctxt != GSS_C_NO_CONTEXT)
+ gss_delete_sec_context(&minor, &ctxt, GSS_C_NO_BUFFER);
+
+ return ret;
+}
diff --git a/plugin/auth_gssapi/gssapi_errmsg.cc b/plugin/auth_gssapi/gssapi_errmsg.cc
new file mode 100644
index 00000000..3e23c573
--- /dev/null
+++ b/plugin/auth_gssapi/gssapi_errmsg.cc
@@ -0,0 +1,80 @@
+/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood,
+Vladislav Vaintroub & MariaDB Corporation
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. 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.
+
+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 HOLDER 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.
+*/
+
+#if defined(__FreeBSD__) || defined(SOLARIS) || defined(__sun)
+#include <gssapi/gssapi.h>
+#else
+#include <gssapi.h>
+#endif
+#include <string.h>
+
+void gssapi_errmsg(OM_uint32 major, OM_uint32 minor, char *buf, size_t size)
+{
+ OM_uint32 message_context;
+ OM_uint32 status_code;
+ OM_uint32 maj_status;
+ OM_uint32 min_status;
+ gss_buffer_desc status_string;
+ char *p= buf;
+ char *end= buf + size - 1;
+ int types[] = {GSS_C_GSS_CODE,GSS_C_MECH_CODE};
+
+ for(int i= 0; i < 2;i++)
+ {
+ message_context= 0;
+ status_code= types[i] == GSS_C_GSS_CODE?major:minor;
+
+ if(!status_code)
+ continue;
+ do
+ {
+ maj_status = gss_display_status(
+ &min_status,
+ status_code,
+ types[i],
+ GSS_C_NO_OID,
+ &message_context,
+ &status_string);
+
+ if(maj_status)
+ break;
+
+ if(p + status_string.length + 2 < end)
+ {
+ memcpy(p,status_string.value, status_string.length);
+ p += status_string.length;
+ *p++ = '.';
+ *p++ = ' ';
+ }
+
+ gss_release_buffer(&min_status, &status_string);
+ }
+ while (message_context != 0);
+ }
+ *p= 0;
+}
diff --git a/plugin/auth_gssapi/gssapi_errmsg.h b/plugin/auth_gssapi/gssapi_errmsg.h
new file mode 100644
index 00000000..26db8439
--- /dev/null
+++ b/plugin/auth_gssapi/gssapi_errmsg.h
@@ -0,0 +1,29 @@
+/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood,
+Vladislav Vaintroub & MariaDB Corporation
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. 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.
+
+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 HOLDER 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.
+*/
+
+extern void gssapi_errmsg(OM_uint32 major, OM_uint32 minor, char *buf, size_t size);
diff --git a/plugin/auth_gssapi/gssapi_server.cc b/plugin/auth_gssapi/gssapi_server.cc
new file mode 100644
index 00000000..db7bda9a
--- /dev/null
+++ b/plugin/auth_gssapi/gssapi_server.cc
@@ -0,0 +1,270 @@
+#include <my_config.h>
+#include <gssapi/gssapi.h>
+#include <stdio.h>
+#include <mysql/plugin_auth.h>
+#include <mysqld_error.h>
+#include <string.h>
+#include "server_plugin.h"
+#include "gssapi_errmsg.h"
+
+static gss_name_t service_name = GSS_C_NO_NAME;
+
+/* This sends the error to the client */
+static void log_error( OM_uint32 major, OM_uint32 minor, const char *msg)
+{
+ if (GSS_ERROR(major))
+ {
+ char sysmsg[1024];
+ gssapi_errmsg(major, minor, sysmsg, sizeof(sysmsg));
+ my_printf_error(ER_UNKNOWN_ERROR,"Server GSSAPI error (major %u, minor %u) : %s -%s",
+ 0, major, minor, msg, sysmsg);
+ }
+ else
+ {
+ my_printf_error(ER_UNKNOWN_ERROR, "Server GSSAPI error : %s", 0, msg);
+ }
+}
+
+
+/*
+ Generate default principal service name formatted as principal name "mariadb/server.fqdn@REALM"
+*/
+#include <krb5.h>
+#ifdef HAVE_KRB5_XFREE
+#define krb5_free_unparsed_name(a,b) krb5_xfree(b)
+#endif
+static char* get_default_principal_name()
+{
+ static char default_name[1024];
+ char *unparsed_name= NULL;
+ krb5_context context= NULL;
+ krb5_principal principal= NULL;
+ krb5_keyblock *key= NULL;
+
+ if(krb5_init_context(&context))
+ {
+ my_printf_error(1, "GSSAPI plugin : krb5_init_context failed",
+ ME_ERROR_LOG | ME_WARNING);
+ goto cleanup;
+ }
+
+ if (krb5_sname_to_principal(context, NULL, "mariadb", KRB5_NT_SRV_HST, &principal))
+ {
+ my_printf_error(1, "GSSAPI plugin : krb5_sname_to_principal failed",
+ ME_ERROR_LOG | ME_WARNING);
+ goto cleanup;
+ }
+
+ if (krb5_unparse_name(context, principal, &unparsed_name))
+ {
+ my_printf_error(1, "GSSAPI plugin : krb5_unparse_name failed",
+ ME_ERROR_LOG | ME_WARNING);
+ goto cleanup;
+ }
+
+ /* Check for entry in keytab */
+ if (krb5_kt_read_service_key(context, NULL, principal, 0, (krb5_enctype)0, &key))
+ {
+ my_printf_error(1, "GSSAPI plugin : default principal '%s' not found in keytab",
+ ME_ERROR_LOG | ME_WARNING, unparsed_name);
+ goto cleanup;
+ }
+
+ strncpy(default_name, unparsed_name, sizeof(default_name)-1);
+
+cleanup:
+ if (key)
+ krb5_free_keyblock(context, key);
+ if (unparsed_name)
+ krb5_free_unparsed_name(context, unparsed_name);
+ if (principal)
+ krb5_free_principal(context, principal);
+ if (context)
+ krb5_free_context(context);
+
+ return default_name;
+}
+
+
+int plugin_init()
+{
+ gss_buffer_desc principal_name_buf;
+ OM_uint32 major= 0, minor= 0;
+ gss_cred_id_t cred= GSS_C_NO_CREDENTIAL;
+
+ if(srv_keytab_path && srv_keytab_path[0])
+ {
+ setenv("KRB5_KTNAME", srv_keytab_path, 1);
+ }
+
+ if(!srv_principal_name || !srv_principal_name[0])
+ srv_principal_name= get_default_principal_name();
+
+ /* import service principal from plain text */
+ if(srv_principal_name && srv_principal_name[0])
+ {
+ my_printf_error(1, "GSSAPI plugin : using principal name '%s'",
+ ME_ERROR_LOG | ME_NOTE, srv_principal_name);
+ principal_name_buf.length= strlen(srv_principal_name);
+ principal_name_buf.value= srv_principal_name;
+ major= gss_import_name(&minor, &principal_name_buf, GSS_C_NT_USER_NAME, &service_name);
+ if(GSS_ERROR(major))
+ {
+ log_error(major, minor, "gss_import_name");
+ return -1;
+ }
+ }
+ else
+ {
+ service_name= GSS_C_NO_NAME;
+ }
+
+ /* Check if SPN configuration is OK */
+ major= gss_acquire_cred(&minor, service_name, GSS_C_INDEFINITE,
+ GSS_C_NO_OID_SET, GSS_C_ACCEPT, &cred, NULL,
+ NULL);
+
+ if (GSS_ERROR(major))
+ {
+ log_error(major, minor, "gss_acquire_cred failed");
+ return -1;
+ }
+ gss_release_cred(&minor, &cred);
+
+ return 0;
+}
+
+int plugin_deinit()
+{
+ if (service_name != GSS_C_NO_NAME)
+ {
+ OM_uint32 minor;
+ gss_release_name(&minor, &service_name);
+ }
+ return 0;
+}
+
+
+int auth_server(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *auth_info)
+{
+
+ int rc= CR_ERROR; /* return code */
+
+ /* GSSAPI related fields */
+ OM_uint32 major= 0, minor= 0, flags= 0;
+ gss_cred_id_t cred= GSS_C_NO_CREDENTIAL; /* credential identifier */
+ gss_ctx_id_t ctxt= GSS_C_NO_CONTEXT; /* context identifier */
+ gss_name_t client_name;
+ gss_buffer_desc client_name_buf, input, output;
+ char *client_name_str;
+ const char *user= 0;
+ size_t userlen= 0;
+ int use_full_name= 0;
+
+ /* server acquires credential */
+ major= gss_acquire_cred(&minor, service_name, GSS_C_INDEFINITE,
+ GSS_C_NO_OID_SET, GSS_C_ACCEPT, &cred, NULL,
+ NULL);
+
+ if (GSS_ERROR(major))
+ {
+ log_error(major, minor, "gss_acquire_cred failed");
+ goto cleanup;
+ }
+
+ input.length= 0;
+ input.value= NULL;
+ do
+ {
+ /* receive token from peer */
+ int len= vio->read_packet(vio, (unsigned char **) &input.value);
+ if (len < 0)
+ {
+ log_error(0, 0, "fail to read token from client");
+ goto cleanup;
+ }
+ if (!user)
+ {
+ if (auth_info->auth_string_length > 0)
+ {
+ use_full_name= 1;
+ user= auth_info->auth_string;
+ userlen= auth_info->auth_string_length;
+ }
+ else
+ {
+ use_full_name= 0;
+ user= auth_info->user_name;
+ userlen= auth_info->user_name_length;
+ }
+ }
+
+ input.length= len;
+ major= gss_accept_sec_context(&minor, &ctxt, cred, &input,
+ GSS_C_NO_CHANNEL_BINDINGS, &client_name,
+ NULL, &output, &flags, NULL, NULL);
+ if (GSS_ERROR(major))
+ {
+
+ log_error(major, minor, "gss_accept_sec_context");
+ rc= CR_ERROR;
+ goto cleanup;
+ }
+
+ /* send token to peer */
+ if (output.length)
+ {
+ if (vio->write_packet(vio, (const unsigned char *) output.value, output.length))
+ {
+ gss_release_buffer(&minor, &output);
+ log_error(major, minor, "communication error(write)");
+ goto cleanup;
+ }
+ gss_release_buffer(&minor, &output);
+ }
+ } while (major & GSS_S_CONTINUE_NEEDED);
+
+ /* extract plain text client name */
+ major= gss_display_name(&minor, client_name, &client_name_buf, NULL);
+ if (GSS_ERROR(major))
+ {
+ log_error(major, minor, "gss_display_name");
+ goto cleanup;
+ }
+
+ client_name_str= (char *)client_name_buf.value;
+
+ /*
+ * Compare input user name with the actual one. Return success if
+ * the names match exactly, or if use_full_name parameter is not set
+ * up to the '@' separator.
+ */
+ if ((userlen == client_name_buf.length) ||
+ (!use_full_name
+ && userlen < client_name_buf.length
+ && client_name_str[userlen] == '@'))
+ {
+ if (user && strncmp(client_name_str, user, userlen) == 0)
+ {
+ rc= CR_OK;
+ }
+ }
+
+ if(rc != CR_OK)
+ {
+ my_printf_error(ER_ACCESS_DENIED_ERROR,
+ "GSSAPI name mismatch, requested '%s', actual name '%.*s'",
+ 0, user, (int)client_name_buf.length, client_name_str);
+ }
+
+ gss_release_buffer(&minor, &client_name_buf);
+
+
+cleanup:
+ if (ctxt != GSS_C_NO_CONTEXT)
+ gss_delete_sec_context(&minor, &ctxt, GSS_C_NO_BUFFER);
+ if (cred != GSS_C_NO_CREDENTIAL)
+ gss_release_cred(&minor, &cred);
+
+ return(rc);
+}
diff --git a/plugin/auth_gssapi/mysql-test/auth_gssapi/basic.result b/plugin/auth_gssapi/mysql-test/auth_gssapi/basic.result
new file mode 100644
index 00000000..b7cf3d8e
--- /dev/null
+++ b/plugin/auth_gssapi/mysql-test/auth_gssapi/basic.result
@@ -0,0 +1,26 @@
+INSTALL SONAME 'auth_gssapi';
+Warnings:
+Note 1105 SSPI: using principal name 'localhost', mech 'Negotiate'
+CREATE USER 'GSSAPI_SHORTNAME' IDENTIFIED WITH gssapi;
+connect con1,localhost,$GSSAPI_SHORTNAME,,;
+SELECT USER(),CURRENT_USER();
+USER() CURRENT_USER()
+GSSAPI_SHORTNAME@localhost GSSAPI_SHORTNAME@%
+disconnect con1;
+connection default;
+DROP USER 'GSSAPI_SHORTNAME';
+CREATE USER nosuchuser IDENTIFIED WITH gssapi;
+ERROR 28000: GSSAPI name mismatch, requested 'nosuchuser', actual name 'GSSAPI_SHORTNAME'
+DROP USER nosuchuser;
+CREATE USER usr1 IDENTIFIED WITH gssapi as 'GSSAPI_FULLNAME';
+connect con1,localhost,usr1,,;
+SELECT USER(),CURRENT_USER();
+USER() CURRENT_USER()
+usr1@localhost usr1@%
+disconnect con1;
+connection default;
+DROP USER usr1;
+CREATE USER nosuchuser IDENTIFIED WITH gssapi AS 'nosuchuser@EXAMPLE.COM';
+ERROR 28000: GSSAPI name mismatch, requested 'nosuchuser@EXAMPLE.COM', actual name 'GSSAPI_FULLNAME'
+DROP USER nosuchuser;
+UNINSTALL SONAME 'auth_gssapi';
diff --git a/plugin/auth_gssapi/mysql-test/auth_gssapi/basic.test b/plugin/auth_gssapi/mysql-test/auth_gssapi/basic.test
new file mode 100644
index 00000000..2307aa39
--- /dev/null
+++ b/plugin/auth_gssapi/mysql-test/auth_gssapi/basic.test
@@ -0,0 +1,46 @@
+--replace_regex /name '[^']+'/name 'localhost'/
+INSTALL SONAME 'auth_gssapi';
+
+#
+# CREATE USER without 'AS' clause
+#
+--replace_result $GSSAPI_SHORTNAME GSSAPI_SHORTNAME
+eval CREATE USER '$GSSAPI_SHORTNAME' IDENTIFIED WITH gssapi;
+connect (con1,localhost,$GSSAPI_SHORTNAME,,);
+--replace_result $GSSAPI_SHORTNAME GSSAPI_SHORTNAME
+SELECT USER(),CURRENT_USER();
+disconnect con1;
+
+connection default;
+--replace_result $GSSAPI_SHORTNAME GSSAPI_SHORTNAME
+eval DROP USER '$GSSAPI_SHORTNAME';
+
+CREATE USER nosuchuser IDENTIFIED WITH gssapi;
+--disable_query_log
+--replace_regex /actual name '.*'/actual name 'GSSAPI_SHORTNAME'/
+--error ER_ACCESS_DENIED_ERROR
+connect (con1,localhost,nosuchuser,,);
+--enable_query_log
+DROP USER nosuchuser;
+
+#
+# CREATE USER with 'AS' clause
+#
+--replace_result $GSSAPI_FULLNAME GSSAPI_FULLNAME
+eval CREATE USER usr1 IDENTIFIED WITH gssapi as '$GSSAPI_FULLNAME';
+connect (con1,localhost,usr1,,);
+--replace_result $GSSAPI_FULLNAME GSSAPI_FULLNAME
+SELECT USER(),CURRENT_USER();
+disconnect con1;
+connection default;
+DROP USER usr1;
+
+CREATE USER nosuchuser IDENTIFIED WITH gssapi AS 'nosuchuser@EXAMPLE.COM';
+--disable_query_log
+--replace_regex /actual name '.*'/actual name 'GSSAPI_FULLNAME'/
+--error ER_ACCESS_DENIED_ERROR
+connect (con1,localhost,nosuchuser,,);
+--enable_query_log
+DROP USER nosuchuser;
+
+UNINSTALL SONAME 'auth_gssapi'; \ No newline at end of file
diff --git a/plugin/auth_gssapi/mysql-test/auth_gssapi/multiauth.result b/plugin/auth_gssapi/mysql-test/auth_gssapi/multiauth.result
new file mode 100644
index 00000000..c65eb7a8
--- /dev/null
+++ b/plugin/auth_gssapi/mysql-test/auth_gssapi/multiauth.result
@@ -0,0 +1,34 @@
+INSTALL SONAME 'auth_gssapi';
+Warnings:
+Note 1105 SSPI: using principal name 'localhost', mech 'Negotiate'
+CREATE USER 'nosuchuser' IDENTIFIED WITH gssapi OR mysql_native_password as password("good");
+connect(localhost,nosuchuser,,test,MASTER_MYPORT,MASTER_MYSOCK);
+connect con1,localhost,nosuchuser,,;
+ERROR 28000: Access denied for user 'nosuchuser'@'localhost' (using password: NO)
+connect con1,localhost,nosuchuser,good,;
+SELECT USER(),CURRENT_USER();
+USER() CURRENT_USER()
+nosuchuser@localhost nosuchuser@%
+disconnect con1;
+connection default;
+DROP USER nosuchuser;
+CREATE USER 'nosuchuser' IDENTIFIED WITH mysql_native_password as password("good") OR gssapi;
+connect(localhost,nosuchuser,,test,MASTER_MYPORT,MASTER_MYSOCK);
+connect con1,localhost,nosuchuser,,;
+ERROR 28000: GSSAPI name mismatch, requested 'nosuchuser', actual name 'GSSAPI_SHORTNAME'
+connect con1,localhost,nosuchuser,good,;
+SELECT USER(),CURRENT_USER();
+USER() CURRENT_USER()
+nosuchuser@localhost nosuchuser@%
+disconnect con1;
+connection default;
+DROP USER nosuchuser;
+CREATE USER 'GSSAPI_SHORTNAME' IDENTIFIED WITH mysql_native_password as password("good") OR gssapi;
+connect con1,localhost,$GSSAPI_SHORTNAME,,;
+SELECT USER(),CURRENT_USER();
+USER() CURRENT_USER()
+GSSAPI_SHORTNAME@localhost GSSAPI_SHORTNAME@%
+disconnect con1;
+connection default;
+DROP USER 'GSSAPI_SHORTNAME';
+UNINSTALL SONAME 'auth_gssapi';
diff --git a/plugin/auth_gssapi/mysql-test/auth_gssapi/multiauth.test b/plugin/auth_gssapi/mysql-test/auth_gssapi/multiauth.test
new file mode 100644
index 00000000..10e1e809
--- /dev/null
+++ b/plugin/auth_gssapi/mysql-test/auth_gssapi/multiauth.test
@@ -0,0 +1,36 @@
+--replace_regex /name '[^']+'/name 'localhost'/
+INSTALL SONAME 'auth_gssapi';
+
+# gssapi,password
+CREATE USER 'nosuchuser' IDENTIFIED WITH gssapi OR mysql_native_password as password("good");
+replace_result $MASTER_MYSOCK MASTER_MYSOCK $MASTER_MYPORT MASTER_MYPORT;
+error ER_ACCESS_DENIED_ERROR;
+connect (con1,localhost,nosuchuser,,);
+connect (con1,localhost,nosuchuser,good,);
+SELECT USER(),CURRENT_USER();
+disconnect con1;
+connection default;
+DROP USER nosuchuser;
+
+# password,gssapi
+CREATE USER 'nosuchuser' IDENTIFIED WITH mysql_native_password as password("good") OR gssapi;
+replace_result $MASTER_MYSOCK MASTER_MYSOCK $MASTER_MYPORT MASTER_MYPORT $GSSAPI_SHORTNAME GSSAPI_SHORTNAME;
+error ER_ACCESS_DENIED_ERROR;
+connect (con1,localhost,nosuchuser,,);
+connect (con1,localhost,nosuchuser,good,);
+SELECT USER(),CURRENT_USER();
+disconnect con1;
+connection default;
+DROP USER nosuchuser;
+
+replace_result $GSSAPI_SHORTNAME GSSAPI_SHORTNAME;
+eval CREATE USER '$GSSAPI_SHORTNAME' IDENTIFIED WITH mysql_native_password as password("good") OR gssapi;
+connect (con1,localhost,$GSSAPI_SHORTNAME,,);
+replace_result $GSSAPI_SHORTNAME GSSAPI_SHORTNAME;
+SELECT USER(),CURRENT_USER();
+disconnect con1;
+connection default;
+replace_result $GSSAPI_SHORTNAME GSSAPI_SHORTNAME;
+eval DROP USER '$GSSAPI_SHORTNAME';
+
+UNINSTALL SONAME 'auth_gssapi';
diff --git a/plugin/auth_gssapi/mysql-test/auth_gssapi/suite.opt b/plugin/auth_gssapi/mysql-test/auth_gssapi/suite.opt
new file mode 100644
index 00000000..3077d70c
--- /dev/null
+++ b/plugin/auth_gssapi/mysql-test/auth_gssapi/suite.opt
@@ -0,0 +1 @@
+--loose-gssapi-keytab-path=$GSSAPI_KEYTAB_PATH --loose-gssapi-principal-name=$GSSAPI_PRINCIPAL_NAME
diff --git a/plugin/auth_gssapi/mysql-test/auth_gssapi/suite.pm b/plugin/auth_gssapi/mysql-test/auth_gssapi/suite.pm
new file mode 100644
index 00000000..aa225536
--- /dev/null
+++ b/plugin/auth_gssapi/mysql-test/auth_gssapi/suite.pm
@@ -0,0 +1,49 @@
+package My::Suite::AuthGSSAPI;
+
+@ISA = qw(My::Suite);
+
+return "No AUTH_GSSAPI plugin" unless $ENV{AUTH_GSSAPI_SO};
+
+return "Not run for embedded server" if $::opt_embedded_server;
+
+# Following environment variables may need to be set
+if ($^O eq "MSWin32")
+{
+ chomp(my $whoami =`whoami /UPN 2>NUL` || `whoami`);
+ my $fullname = $whoami;
+ $fullname =~ s/\\/\\\\/; # SQL escaping for backslash
+ $ENV{'GSSAPI_FULLNAME'} = $fullname;
+ $ENV{'GSSAPI_SHORTNAME'} = $ENV{'USERNAME'};
+}
+else
+{
+ if (!$ENV{'GSSAPI_FULLNAME'})
+ {
+ my $s = `klist 2>/dev/null |grep 'Default principal: '`;
+ if ($s)
+ {
+ chomp($s);
+ my $fullname = substr($s,19);
+ $ENV{'GSSAPI_FULLNAME'} = $fullname;
+ }
+ }
+ $ENV{'GSSAPI_SHORTNAME'} = (split /@/, $ENV{'GSSAPI_FULLNAME'}) [0];
+}
+
+
+if (!$ENV{'GSSAPI_FULLNAME'} || !$ENV{'GSSAPI_SHORTNAME'})
+{
+ return "Environment variable GSSAPI_SHORTNAME and GSSAPI_FULLNAME need to be set"
+}
+
+if ($::opt_verbose)
+{
+ foreach $var ('GSSAPI_SHORTNAME','GSSAPI_FULLNAME','GSSAPI_KEYTAB_PATH','GSSAPI_PRINCIPAL_NAME')
+ {
+ print "$var=$ENV{$var}\n";
+ }
+}
+sub is_default { 1 }
+
+bless { };
+
diff --git a/plugin/auth_gssapi/server_plugin.cc b/plugin/auth_gssapi/server_plugin.cc
new file mode 100644
index 00000000..4fdad2de
--- /dev/null
+++ b/plugin/auth_gssapi/server_plugin.cc
@@ -0,0 +1,165 @@
+/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood,
+ Vladislav Vaintroub & MariaDB Corporation
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. 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.
+
+ 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 HOLDER 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.
+*/
+
+/**
+ @file
+
+ GSSAPI authentication plugin, server side
+*/
+
+#ifdef _WIN32
+typedef unsigned __int64 my_ulonglong;
+#else
+typedef unsigned long long my_ulonglong;
+#endif
+
+#include <stdlib.h>
+#include <mysqld_error.h>
+#include <typelib.h>
+#include <mysql/plugin_auth.h>
+#include "string.h"
+#include "server_plugin.h"
+#include "common.h"
+
+/* First packet sent from server to client, contains srv_principal_name\0mech\0 */
+static char first_packet[PRINCIPAL_NAME_MAX + MECH_NAME_MAX +2];
+static int first_packet_len;
+
+/*
+ Target name in GSSAPI/SSPI , for Kerberos it is service principal name
+ (often user principal name of the server user will work)
+*/
+char *srv_principal_name;
+char *srv_keytab_path;
+const char *srv_mech_name="";
+unsigned long srv_mech;
+
+/**
+ The main server function of the GSSAPI plugin.
+ */
+static int gssapi_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *auth_info)
+{
+ /* Send first packet with target name and mech name */
+ if (vio->write_packet(vio, (unsigned char *)first_packet, first_packet_len))
+ return CR_ERROR;
+
+ return auth_server(vio, auth_info);
+}
+
+static int initialize_plugin(void *unused)
+{
+ int rc;
+ rc = plugin_init();
+ if (rc)
+ return rc;
+
+ strcpy(first_packet, srv_principal_name);
+ strcpy(first_packet + strlen(srv_principal_name) + 1,srv_mech_name);
+ first_packet_len = (int)(strlen(srv_principal_name) + strlen(srv_mech_name) + 2);
+
+ return 0;
+}
+
+static int deinitialize_plugin(void *unused)
+{
+ return plugin_deinit();
+}
+
+#ifdef PLUGIN_GSSAPI
+/* system variable */
+static MYSQL_SYSVAR_STR(keytab_path, srv_keytab_path,
+ PLUGIN_VAR_RQCMDARG|PLUGIN_VAR_READONLY,
+ "Keytab file path for Kerberos authentication",
+ NULL,
+ NULL,
+ "");
+#endif
+
+static MYSQL_SYSVAR_STR(principal_name, srv_principal_name,
+ PLUGIN_VAR_RQCMDARG|PLUGIN_VAR_READONLY,
+ "GSSAPI target name - service principal name for Kerberos authentication.",
+ NULL,
+ NULL,
+ "");
+#ifdef PLUGIN_SSPI
+static const char* mech_names[] = {
+ "Kerberos",
+ "Negotiate",
+ "",
+ NULL
+};
+static TYPELIB mech_name_typelib = {
+ 3,
+ "mech_name_typelib",
+ mech_names,
+ NULL
+};
+static MYSQL_SYSVAR_ENUM(mech_name, srv_mech,
+ PLUGIN_VAR_RQCMDARG|PLUGIN_VAR_READONLY,
+ "GSSAPI mechanism",
+ NULL,
+ NULL,
+ 2,&mech_name_typelib);
+#endif
+
+static struct st_mysql_sys_var *system_variables[]= {
+ MYSQL_SYSVAR(principal_name),
+#ifdef PLUGIN_SSPI
+ MYSQL_SYSVAR(mech_name),
+#endif
+#ifdef PLUGIN_GSSAPI
+ MYSQL_SYSVAR(keytab_path),
+#endif
+ NULL
+};
+
+/* Register authentication plugin */
+static struct st_mysql_auth server_handler= {
+ MYSQL_AUTHENTICATION_INTERFACE_VERSION,
+ "auth_gssapi_client",
+ gssapi_auth, NULL, NULL
+};
+
+maria_declare_plugin(gssapi_server)
+{
+ MYSQL_AUTHENTICATION_PLUGIN,
+ &server_handler,
+ "gssapi",
+ "Shuang Qiu, Robbie Harwood, Vladislav Vaintroub",
+ "Plugin for GSSAPI/SSPI based authentication.",
+ PLUGIN_LICENSE_BSD,
+ initialize_plugin,
+ deinitialize_plugin, /* destructor */
+ 0x0100, /* version */
+ NULL, /* status variables */
+ system_variables, /* system variables */
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
+
diff --git a/plugin/auth_gssapi/server_plugin.h b/plugin/auth_gssapi/server_plugin.h
new file mode 100644
index 00000000..84552d3a
--- /dev/null
+++ b/plugin/auth_gssapi/server_plugin.h
@@ -0,0 +1,51 @@
+/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood,
+Vladislav Vaintroub & MariaDB Corporation
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. 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.
+
+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 HOLDER 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.
+*/
+
+/* Plugin variables*/
+#include <mysql/plugin_auth.h>
+typedef enum
+{
+ PLUGIN_MECH_KERBEROS = 0,
+ PLUGIN_MECH_SPNEGO = 1,
+ PLUGIN_MECH_DEFAULT = 2
+}PLUGIN_MECH;
+
+extern unsigned long srv_mech;
+extern char *srv_principal_name;
+extern const char *srv_mech_name;
+extern char *srv_keytab_path;
+/*
+ Check, with GSSAPI/SSPI username of logged on user.
+
+ Depending on use_full_name parameter, compare either full name
+ (principal name like user@real), or local name (first component)
+*/
+int plugin_init();
+int plugin_deinit();
+
+int auth_server(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *auth_info);
diff --git a/plugin/auth_gssapi/sspi.h b/plugin/auth_gssapi/sspi.h
new file mode 100644
index 00000000..34b8a56a
--- /dev/null
+++ b/plugin/auth_gssapi/sspi.h
@@ -0,0 +1,38 @@
+/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood,
+Vladislav Vaintroub & MariaDB Corporation
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. 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.
+
+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 HOLDER 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.
+*/
+
+#define SECURITY_WIN32
+#include <windows.h>
+#include <sspi.h>
+#include <SecExt.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#define SSPI_MAX_TOKEN_SIZE 50000
+#define SEC_ERROR(err) (err < 0)
+extern void sspi_errmsg(int err, char *buf, size_t size); \ No newline at end of file
diff --git a/plugin/auth_gssapi/sspi_client.cc b/plugin/auth_gssapi/sspi_client.cc
new file mode 100644
index 00000000..61249dd1
--- /dev/null
+++ b/plugin/auth_gssapi/sspi_client.cc
@@ -0,0 +1,183 @@
+/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood,
+Vladislav Vaintroub & MariaDB Corporation
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. 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.
+
+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 HOLDER 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.
+*/
+
+#define SECURITY_WIN32
+#include <windows.h>
+#include <sspi.h>
+#include <SecExt.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include <mysql/plugin_auth.h>
+#include <mysql.h>
+#include <mysqld_error.h>
+
+#include "sspi.h"
+
+extern void log_client_error(MYSQL *mysql, const char *fmt, ...);
+static void log_error(MYSQL *mysql, SECURITY_STATUS err, const char *msg)
+{
+ if (err)
+ {
+ char buf[1024];
+ sspi_errmsg(err, buf, sizeof(buf));
+ log_client_error(mysql, "SSPI client error 0x%x - %s - %s", err, msg, buf);
+ }
+ else
+ {
+ log_client_error(mysql, "SSPI client error %s", msg);
+ }
+}
+
+
+/** Client side authentication*/
+int auth_client(char *principal_name, char *mech, MYSQL *mysql, MYSQL_PLUGIN_VIO *vio)
+{
+
+ int ret;
+ CredHandle cred;
+ CtxtHandle ctxt;
+ ULONG attribs = 0;
+ TimeStamp lifetime;
+ SECURITY_STATUS sspi_err;
+
+ SecBufferDesc inbuf_desc;
+ SecBuffer inbuf;
+ SecBufferDesc outbuf_desc;
+ SecBuffer outbuf;
+ PBYTE out = NULL;
+
+ ret= CR_ERROR;
+ SecInvalidateHandle(&ctxt);
+ SecInvalidateHandle(&cred);
+
+ if (!mech || strcmp(mech, "Negotiate") != 0)
+ {
+ mech= "Kerberos";
+ }
+
+ sspi_err = AcquireCredentialsHandle(
+ NULL,
+ mech,
+ SECPKG_CRED_OUTBOUND,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &cred,
+ &lifetime);
+
+ if (SEC_ERROR(sspi_err))
+ {
+ log_error(mysql, sspi_err, "AcquireCredentialsHandle");
+ return CR_ERROR;
+ }
+
+ out = (PBYTE)malloc(SSPI_MAX_TOKEN_SIZE);
+ if (!out)
+ {
+ log_error(mysql, SEC_E_OK, "memory allocation error");
+ goto cleanup;
+ }
+
+ /* Prepare buffers */
+ inbuf_desc.ulVersion = SECBUFFER_VERSION;
+ inbuf_desc.cBuffers = 1;
+ inbuf_desc.pBuffers = &inbuf;
+ inbuf.BufferType = SECBUFFER_TOKEN;
+ inbuf.cbBuffer = 0;
+ inbuf.pvBuffer = NULL;
+
+ outbuf_desc.ulVersion = SECBUFFER_VERSION;
+ outbuf_desc.cBuffers = 1;
+ outbuf_desc.pBuffers = &outbuf;
+ outbuf.BufferType = SECBUFFER_TOKEN;
+ outbuf.pvBuffer = out;
+
+ do
+ {
+ outbuf.cbBuffer= SSPI_MAX_TOKEN_SIZE;
+ sspi_err= InitializeSecurityContext(
+ &cred,
+ SecIsValidHandle(&ctxt) ? &ctxt : NULL,
+ principal_name,
+ 0,
+ 0,
+ SECURITY_NATIVE_DREP,
+ inbuf.cbBuffer ? &inbuf_desc : NULL,
+ 0,
+ &ctxt,
+ &outbuf_desc,
+ &attribs,
+ &lifetime);
+ if (SEC_ERROR(sspi_err))
+ {
+ log_error(mysql, sspi_err, "InitializeSecurityContext");
+ goto cleanup;
+ }
+ if (sspi_err != SEC_E_OK && sspi_err != SEC_I_CONTINUE_NEEDED)
+ {
+ log_error(mysql, sspi_err, "Unexpected response from InitializeSecurityContext");
+ goto cleanup;
+ }
+
+ if (outbuf.cbBuffer)
+ {
+ /* send credential to server */
+ if (vio->write_packet(vio, (unsigned char *)outbuf.pvBuffer, outbuf.cbBuffer))
+ {
+ /* Server error packet contains detailed message. */
+ ret= CR_OK_HANDSHAKE_COMPLETE;
+ goto cleanup;
+ }
+ }
+
+ if (sspi_err == SEC_I_CONTINUE_NEEDED)
+ {
+ int len= vio->read_packet(vio, (unsigned char **)&inbuf.pvBuffer);
+ if (len <= 0)
+ {
+ /* Server side error is in the last server packet. */
+ ret= CR_OK_HANDSHAKE_COMPLETE;
+ goto cleanup;
+ }
+ inbuf.cbBuffer= len;
+ }
+ } while (sspi_err == SEC_I_CONTINUE_NEEDED);
+
+ ret= CR_OK;
+
+cleanup:
+
+ if (SecIsValidHandle(&ctxt))
+ DeleteSecurityContext(&ctxt);
+ if (SecIsValidHandle(&cred))
+ FreeCredentialsHandle(&cred);
+ free(out);
+ return ret;
+}
diff --git a/plugin/auth_gssapi/sspi_errmsg.cc b/plugin/auth_gssapi/sspi_errmsg.cc
new file mode 100644
index 00000000..8e59da6f
--- /dev/null
+++ b/plugin/auth_gssapi/sspi_errmsg.cc
@@ -0,0 +1,150 @@
+/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood,
+Vladislav Vaintroub & MariaDB Corporation
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. 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.
+
+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 HOLDER 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.
+*/
+
+#include <windows.h>
+#include <stdio.h>
+
+#define ERRSYM(x) {x, #x}
+static struct {
+ int error;
+ const char *sym;
+} error_symbols[] =
+{
+ ERRSYM(SEC_E_OK),
+ ERRSYM(SEC_E_INSUFFICIENT_MEMORY),
+ ERRSYM(SEC_E_INVALID_HANDLE),
+ ERRSYM(SEC_E_UNSUPPORTED_FUNCTION),
+ ERRSYM(SEC_E_TARGET_UNKNOWN),
+ ERRSYM(SEC_E_INTERNAL_ERROR),
+ ERRSYM(SEC_E_SECPKG_NOT_FOUND),
+ ERRSYM(SEC_E_NOT_OWNER),
+ ERRSYM(SEC_E_CANNOT_INSTALL),
+ ERRSYM(SEC_E_INVALID_TOKEN),
+ ERRSYM(SEC_E_CANNOT_PACK),
+ ERRSYM(SEC_E_QOP_NOT_SUPPORTED),
+ ERRSYM(SEC_E_NO_IMPERSONATION),
+ ERRSYM(SEC_E_LOGON_DENIED),
+ ERRSYM(SEC_E_UNKNOWN_CREDENTIALS),
+ ERRSYM(SEC_E_NO_CREDENTIALS),
+ ERRSYM(SEC_E_MESSAGE_ALTERED),
+ ERRSYM(SEC_E_OUT_OF_SEQUENCE),
+ ERRSYM(SEC_E_NO_AUTHENTICATING_AUTHORITY),
+ ERRSYM(SEC_E_BAD_PKGID),
+ ERRSYM(SEC_E_CONTEXT_EXPIRED),
+ ERRSYM(SEC_E_INCOMPLETE_MESSAGE),
+ ERRSYM(SEC_E_INCOMPLETE_CREDENTIALS),
+ ERRSYM(SEC_E_BUFFER_TOO_SMALL),
+ ERRSYM(SEC_E_WRONG_PRINCIPAL),
+ ERRSYM(SEC_E_TIME_SKEW),
+ ERRSYM(SEC_E_UNTRUSTED_ROOT),
+ ERRSYM(SEC_E_ILLEGAL_MESSAGE),
+ ERRSYM(SEC_E_CERT_UNKNOWN),
+ ERRSYM(SEC_E_CERT_EXPIRED),
+ ERRSYM(SEC_E_ENCRYPT_FAILURE),
+ ERRSYM(SEC_E_DECRYPT_FAILURE),
+ ERRSYM(SEC_E_ALGORITHM_MISMATCH),
+ ERRSYM(SEC_E_SECURITY_QOS_FAILED),
+ ERRSYM(SEC_E_UNFINISHED_CONTEXT_DELETED),
+ ERRSYM(SEC_E_NO_TGT_REPLY),
+ ERRSYM(SEC_E_NO_IP_ADDRESSES),
+ ERRSYM(SEC_E_WRONG_CREDENTIAL_HANDLE),
+ ERRSYM(SEC_E_CRYPTO_SYSTEM_INVALID),
+ ERRSYM(SEC_E_MAX_REFERRALS_EXCEEDED),
+ ERRSYM(SEC_E_MUST_BE_KDC),
+ ERRSYM(SEC_E_STRONG_CRYPTO_NOT_SUPPORTED),
+ ERRSYM(SEC_E_TOO_MANY_PRINCIPALS),
+ ERRSYM(SEC_E_NO_PA_DATA),
+ ERRSYM(SEC_E_PKINIT_NAME_MISMATCH),
+ ERRSYM(SEC_E_SMARTCARD_LOGON_REQUIRED),
+ ERRSYM(SEC_E_SHUTDOWN_IN_PROGRESS),
+ ERRSYM(SEC_E_KDC_INVALID_REQUEST),
+ ERRSYM(SEC_E_KDC_UNABLE_TO_REFER),
+ ERRSYM(SEC_E_KDC_UNKNOWN_ETYPE),
+ ERRSYM(SEC_E_UNSUPPORTED_PREAUTH),
+ ERRSYM(SEC_E_DELEGATION_REQUIRED),
+ ERRSYM(SEC_E_BAD_BINDINGS),
+ ERRSYM(SEC_E_MULTIPLE_ACCOUNTS),
+ ERRSYM(SEC_E_NO_KERB_KEY),
+ ERRSYM(SEC_E_CERT_WRONG_USAGE),
+ ERRSYM(SEC_E_DOWNGRADE_DETECTED),
+ ERRSYM(SEC_E_SMARTCARD_CERT_REVOKED),
+ ERRSYM(SEC_E_ISSUING_CA_UNTRUSTED),
+ ERRSYM(SEC_E_REVOCATION_OFFLINE_C),
+ ERRSYM(SEC_E_PKINIT_CLIENT_FAILURE),
+ ERRSYM(SEC_E_SMARTCARD_CERT_EXPIRED),
+ ERRSYM(SEC_E_NO_S4U_PROT_SUPPORT),
+ ERRSYM(SEC_E_CROSSREALM_DELEGATION_FAILURE),
+ ERRSYM(SEC_E_REVOCATION_OFFLINE_KDC),
+ ERRSYM(SEC_E_ISSUING_CA_UNTRUSTED_KDC),
+ ERRSYM(SEC_E_KDC_CERT_EXPIRED),
+ ERRSYM(SEC_E_KDC_CERT_REVOKED),
+ ERRSYM(SEC_E_INVALID_PARAMETER),
+ ERRSYM(SEC_E_DELEGATION_POLICY),
+ ERRSYM(SEC_E_POLICY_NLTM_ONLY),
+ ERRSYM(SEC_E_NO_CONTEXT),
+ ERRSYM(SEC_E_PKU2U_CERT_FAILURE),
+ ERRSYM(SEC_E_MUTUAL_AUTH_FAILED),
+ ERRSYM(SEC_E_NO_SPM),
+ ERRSYM(SEC_E_NOT_SUPPORTED),
+ {0,0}
+};
+
+void sspi_errmsg(int err, char *buf, size_t size)
+{
+ buf[size - 1] = 0;
+ size_t len;
+
+ for (size_t i= 0; error_symbols[i].sym; i++)
+ {
+ if (error_symbols[i].error == err)
+ {
+ size_t len= strlen(error_symbols[i].sym);
+ if (len + 2 < size)
+ {
+ memcpy(buf, error_symbols[i].sym, len);
+ buf[len]= ' ';
+ buf += len + 1;
+ size-= len + 1;
+ }
+ break;
+ }
+ }
+
+ len = FormatMessageA(
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
+ err, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+ buf, (DWORD)size, NULL);
+
+ if(len > 0)
+ {
+ /* Trim trailing \n\r*/
+ char *p;
+ for(p= buf + len;p > buf && (*p == '\n' || *p=='\r' || *p == 0);p--)
+ *p= 0;
+ }
+}
diff --git a/plugin/auth_gssapi/sspi_server.cc b/plugin/auth_gssapi/sspi_server.cc
new file mode 100644
index 00000000..44aa5051
--- /dev/null
+++ b/plugin/auth_gssapi/sspi_server.cc
@@ -0,0 +1,330 @@
+/* Copyright (c) 2015, Shuang Qiu, Robbie Harwood,
+Vladislav Vaintroub & MariaDB Corporation
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. 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.
+
+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 HOLDER 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.
+*/
+
+#include "sspi.h"
+#include "common.h"
+#include "server_plugin.h"
+#include <mysql/plugin_auth.h>
+#include <mysqld_error.h>
+
+
+/* This sends the error to the client */
+static void log_error(SECURITY_STATUS err, const char *msg)
+{
+ if (err)
+ {
+ char buf[1024];
+ sspi_errmsg(err, buf, sizeof(buf));
+ my_printf_error(ER_UNKNOWN_ERROR, "SSPI server error 0x%x - %s - %s", 0, err, msg, buf);
+ }
+ else
+ {
+ my_printf_error(ER_UNKNOWN_ERROR, "SSPI server error %s", 0, msg);
+ }
+
+}
+
+static char INVALID_KERBEROS_PRINCIPAL[] = "localhost";
+
+static char *get_default_principal_name()
+{
+ static char default_principal[PRINCIPAL_NAME_MAX +1];
+ ULONG size= sizeof(default_principal);
+
+ if (GetUserNameEx(NameUserPrincipal,default_principal,&size))
+ return default_principal;
+
+ size= sizeof(default_principal);
+ if (GetUserNameEx(NameServicePrincipal,default_principal,&size))
+ return default_principal;
+
+ char domain[PRINCIPAL_NAME_MAX+1];
+ char host[PRINCIPAL_NAME_MAX+1];
+ size= sizeof(domain);
+ if (GetComputerNameEx(ComputerNameDnsDomain,domain,&size) && size > 0)
+ {
+ size= sizeof(host);
+ if (GetComputerNameEx(ComputerNameDnsHostname,host,&size))
+ {
+ _snprintf(default_principal,sizeof(default_principal),"%s$@%s",host, domain);
+ return default_principal;
+ }
+ }
+ /* Unable to retrieve useful name, return something */
+ return INVALID_KERBEROS_PRINCIPAL;
+}
+
+
+/* Extract client name from SSPI context */
+static int get_client_name_from_context(CtxtHandle *ctxt,
+ char *name,
+ size_t name_len,
+ int use_full_name)
+{
+ SecPkgContext_NativeNames native_names;
+ SECURITY_STATUS sspi_ret;
+ char *p;
+
+ sspi_ret= QueryContextAttributes(ctxt, SECPKG_ATTR_NATIVE_NAMES, &native_names);
+ if (sspi_ret == SEC_E_OK)
+ {
+ /* Extract user from Kerberos principal name user@realm */
+ if(!use_full_name)
+ {
+ p = strrchr(native_names.sClientName,'@');
+ if(p)
+ *p = 0;
+ }
+ strncpy(name, native_names.sClientName, name_len);
+
+ if (native_names.sClientName)
+ FreeContextBuffer(native_names.sClientName);
+ if (native_names.sServerName)
+ FreeContextBuffer(native_names.sServerName);
+
+ return CR_OK;
+ }
+
+ sspi_ret= ImpersonateSecurityContext(ctxt);
+ if (sspi_ret == SEC_E_OK)
+ {
+ ULONG len= (ULONG)name_len;
+ if (!GetUserNameEx(NameSamCompatible, name, &len))
+ {
+ log_error(GetLastError(), "GetUserNameEx");
+ RevertSecurityContext(ctxt);
+ return CR_ERROR;
+ }
+ RevertSecurityContext(ctxt);
+
+ /* Extract user from Windows name realm\user */
+ if (!use_full_name)
+ {
+ p = strrchr(name, '\\');
+ if (p)
+ {
+ p++;
+ memmove(name, p, name + len + 1 - p);
+ }
+ }
+ return CR_OK;
+ }
+
+ log_error(sspi_ret, "ImpersonateSecurityContext");
+ return CR_ERROR;
+}
+
+
+int auth_server(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *auth_info)
+{
+ int ret;
+ SECURITY_STATUS sspi_ret;
+ ULONG attribs = 0;
+ TimeStamp lifetime;
+ CredHandle cred;
+ CtxtHandle ctxt;
+
+ SecBufferDesc inbuf_desc;
+ SecBuffer inbuf;
+ SecBufferDesc outbuf_desc;
+ SecBuffer outbuf;
+ void* out= NULL;
+ char client_name[MYSQL_USERNAME_LENGTH + 1];
+ const char *user= 0;
+ int compare_full_name;
+
+ ret= CR_ERROR;
+ SecInvalidateHandle(&cred);
+ SecInvalidateHandle(&ctxt);
+
+ out= malloc(SSPI_MAX_TOKEN_SIZE);
+ if (!out)
+ {
+ log_error(SEC_E_OK, "memory allocation failed");
+ goto cleanup;
+ }
+ sspi_ret= AcquireCredentialsHandle(
+ srv_principal_name,
+ (LPSTR)srv_mech_name,
+ SECPKG_CRED_INBOUND,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &cred,
+ &lifetime);
+
+ if (SEC_ERROR(sspi_ret))
+ {
+ log_error(sspi_ret, "AcquireCredentialsHandle failed");
+ goto cleanup;
+ }
+
+ inbuf.cbBuffer= 0;
+ inbuf.BufferType= SECBUFFER_TOKEN;
+ inbuf.pvBuffer= NULL;
+ inbuf_desc.ulVersion= SECBUFFER_VERSION;
+ inbuf_desc.cBuffers= 1;
+ inbuf_desc.pBuffers= &inbuf;
+
+ outbuf.BufferType= SECBUFFER_TOKEN;
+ outbuf.cbBuffer= SSPI_MAX_TOKEN_SIZE;
+ outbuf.pvBuffer= out;
+
+ outbuf_desc.ulVersion= SECBUFFER_VERSION;
+ outbuf_desc.cBuffers= 1;
+ outbuf_desc.pBuffers= &outbuf;
+
+ do
+ {
+ /* Read SSPI blob from client. */
+ int len= vio->read_packet(vio, (unsigned char **)&inbuf.pvBuffer);
+ if (len < 0)
+ {
+ log_error(SEC_E_OK, "communication error(read)");
+ goto cleanup;
+ }
+ if (!user)
+ {
+ if (auth_info->auth_string_length > 0)
+ {
+ compare_full_name= 1;
+ user= auth_info->auth_string;
+ }
+ else
+ {
+ compare_full_name= 0;
+ user= auth_info->user_name;
+ }
+ }
+ inbuf.cbBuffer= len;
+ outbuf.cbBuffer= SSPI_MAX_TOKEN_SIZE;
+ sspi_ret= AcceptSecurityContext(
+ &cred,
+ SecIsValidHandle(&ctxt) ? &ctxt : NULL,
+ &inbuf_desc,
+ attribs,
+ SECURITY_NATIVE_DREP,
+ &ctxt,
+ &outbuf_desc,
+ &attribs,
+ &lifetime);
+
+ if (SEC_ERROR(sspi_ret))
+ {
+ log_error(sspi_ret, "AcceptSecurityContext");
+ goto cleanup;
+ }
+ if (sspi_ret != SEC_E_OK && sspi_ret != SEC_I_CONTINUE_NEEDED)
+ {
+ log_error(sspi_ret, "AcceptSecurityContext unexpected return value");
+ goto cleanup;
+ }
+ if (outbuf.cbBuffer)
+ {
+ /* Send generated blob to client. */
+ if (vio->write_packet(vio, (unsigned char *)outbuf.pvBuffer, outbuf.cbBuffer))
+ {
+ log_error(SEC_E_OK, "communicaton error(write)");
+ goto cleanup;
+ }
+ }
+ } while (sspi_ret == SEC_I_CONTINUE_NEEDED);
+
+ /* Authentication done, now extract and compare user name. */
+ ret= get_client_name_from_context(&ctxt, client_name, MYSQL_USERNAME_LENGTH, compare_full_name);
+ if (ret != CR_OK)
+ goto cleanup;
+
+ /* Always compare case-insensitive on Windows. */
+ ret= _stricmp(client_name, user) == 0 ? CR_OK : CR_ERROR;
+ if (ret != CR_OK)
+ {
+ my_printf_error(ER_ACCESS_DENIED_ERROR,
+ "GSSAPI name mismatch, requested '%s', actual name '%s'",
+ 0, user, client_name);
+ }
+
+cleanup:
+ if (SecIsValidHandle(&ctxt))
+ DeleteSecurityContext(&ctxt);
+
+ if (SecIsValidHandle(&cred))
+ FreeCredentialsHandle(&cred);
+
+ free(out);
+ return ret;
+}
+
+int plugin_init()
+{
+ CredHandle cred;
+ SECURITY_STATUS ret;
+
+ /*
+ Use negotiate by default, which accepts raw kerberos
+ and also NTLM.
+ */
+ if (srv_mech == PLUGIN_MECH_DEFAULT)
+ srv_mech= PLUGIN_MECH_SPNEGO;
+
+ if(srv_mech == PLUGIN_MECH_KERBEROS)
+ srv_mech_name= "Kerberos";
+ else if(srv_mech == PLUGIN_MECH_SPNEGO )
+ srv_mech_name= "Negotiate";
+
+ if(!srv_principal_name[0])
+ {
+ srv_principal_name= get_default_principal_name();
+ }
+ my_printf_error(ER_UNKNOWN_ERROR, "SSPI: using principal name '%s', mech '%s'",
+ ME_ERROR_LOG | ME_NOTE, srv_principal_name, srv_mech_name);
+
+ ret = AcquireCredentialsHandle(
+ srv_principal_name,
+ (LPSTR)srv_mech_name,
+ SECPKG_CRED_INBOUND,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &cred,
+ NULL);
+ if (SEC_ERROR(ret))
+ {
+ log_error(ret, "AcquireCredentialsHandle");
+ return -1;
+ }
+ FreeCredentialsHandle(&cred);
+ return 0;
+}
+
+int plugin_deinit()
+{
+ return 0;
+}
diff --git a/plugin/auth_pam/CMakeLists.txt b/plugin/auth_pam/CMakeLists.txt
new file mode 100644
index 00000000..8d11d174
--- /dev/null
+++ b/plugin/auth_pam/CMakeLists.txt
@@ -0,0 +1,61 @@
+INCLUDE (CheckIncludeFiles)
+INCLUDE (CheckFunctionExists)
+
+CHECK_INCLUDE_FILES (security/pam_ext.h HAVE_PAM_EXT_H)
+CHECK_INCLUDE_FILES (security/pam_appl.h HAVE_PAM_APPL_H)
+CHECK_FUNCTION_EXISTS (strndup HAVE_STRNDUP)
+CHECK_FUNCTION_EXISTS (getgrouplist HAVE_GETGROUPLIST)
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
+
+# Check whether getgrouplist uses gtid_t for second and third arguments.
+SET(CMAKE_REQUIRED_FLAGS -Werror)
+CHECK_C_SOURCE_COMPILES(
+"
+#include <grp.h>
+#include <unistd.h>
+int main() {
+ char *arg_1= 0;
+ gid_t arg_2=0, arg_3;
+ int arg_4;
+ (void)getgrouplist(arg_1,arg_2,&arg_3,&arg_4);
+ return 0;
+}
+"
+HAVE_POSIX_GETGROUPLIST
+)
+SET(CMAKE_REQUIRED_FLAGS)
+
+SET(CMAKE_REQUIRED_LIBRARIES pam)
+CHECK_FUNCTION_EXISTS(pam_syslog HAVE_PAM_SYSLOG)
+SET(CMAKE_REQUIRED_LIBRARIES)
+
+IF(HAVE_PAM_APPL_H AND HAVE_GETGROUPLIST)
+ FIND_LIBRARY(PAM_LIBRARY pam) # for srpm build-depends detection
+ ADD_DEFINITIONS(-D_GNU_SOURCE)
+ MYSQL_ADD_PLUGIN(auth_pam_v1 auth_pam_v1.c LINK_LIBRARIES pam MODULE_ONLY)
+ MYSQL_ADD_PLUGIN(auth_pam auth_pam.c LINK_LIBRARIES pam ${CMAKE_DL_LIBS} MODULE_ONLY)
+ IF (TARGET auth_pam)
+ MYSQL_ADD_EXECUTABLE(auth_pam_tool auth_pam_tool.c DESTINATION ${INSTALL_PLUGINDIR}/auth_pam_tool_dir COMPONENT Server)
+ TARGET_LINK_LIBRARIES(auth_pam_tool pam)
+ INSTALL(CODE "EXECUTE_PROCESS(
+ COMMAND chmod u=rwx,g=,o= auth_pam_tool_dir
+ COMMAND chmod u=rwxs,g=rx,o=rx auth_pam_tool_dir/auth_pam_tool
+ WORKING_DIRECTORY \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${INSTALL_PLUGINDIR}/)"
+ COMPONENT Server)
+ ENDIF()
+ IF(TARGET auth_pam OR TARGET auth_pam_v1)
+ ADD_SUBDIRECTORY(testing)
+ ADD_LIBRARY(pam_user_map MODULE mapper/pam_user_map.c)
+ TARGET_LINK_LIBRARIES(pam_user_map pam)
+ SET_TARGET_PROPERTIES (pam_user_map PROPERTIES PREFIX "")
+ IF(INSTALL_PAMDIR)
+ INSTALL(TARGETS pam_user_map DESTINATION ${INSTALL_PAMDIR} COMPONENT Server)
+ INSTALL(FILES mapper/user_map.conf DESTINATION ${INSTALL_PAMDATADIR} COMPONENT Server)
+ SET(CPACK_RPM_server_USER_FILELIST ${CPACK_RPM_server_USER_FILELIST} "%config(noreplace) ${INSTALL_PAMDATADIR}/*" PARENT_SCOPE)
+ ENDIF()
+ ENDIF()
+ENDIF()
+
+CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/config_auth_pam.h)
diff --git a/plugin/auth_pam/auth_pam.c b/plugin/auth_pam/auth_pam.c
new file mode 100644
index 00000000..35272c6b
--- /dev/null
+++ b/plugin/auth_pam/auth_pam.c
@@ -0,0 +1,254 @@
+/*
+ Copyright (c) 2011, 2020, MariaDB Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
+
+
+#include <config_auth_pam.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <mysql/plugin_auth.h>
+#include "auth_pam_tool.h"
+#include <my_global.h>
+
+#ifndef DBUG_OFF
+static char pam_debug = 0;
+#define PAM_DEBUG(X) do { if (pam_debug) { fprintf X; } } while(0)
+#else
+#define PAM_DEBUG(X) /* no-op */
+#endif
+
+static char winbind_hack = 0;
+
+static char *opt_plugin_dir; /* To be dynamically linked. */
+static const char *tool_name= "auth_pam_tool_dir/auth_pam_tool";
+static const int tool_name_len= 31;
+
+/*
+ sleep_limit is now 5 meaning up to 1 second sleep.
+ each step means 10 times longer sleep, so 6 would mean 10 seconds.
+*/
+static const unsigned int sleep_limit= 5;
+
+static int pam_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
+{
+ int p_to_c[2], c_to_p[2]; /* Parent-to-child and child-to-parent pipes. */
+ pid_t proc_id;
+ int result= CR_ERROR, pkt_len= 0;
+ unsigned char field, *pkt;
+ unsigned int n_sleep= 0;
+ useconds_t sleep_time= 100;
+
+ PAM_DEBUG((stderr, "PAM: opening pipes.\n"));
+ if (pipe(p_to_c) < 0 || pipe(c_to_p) < 0)
+ {
+ /* Error creating pipes. */
+ return CR_ERROR;
+ }
+ PAM_DEBUG((stderr, "PAM: forking.\n"));
+ if ((proc_id= fork()) < 0)
+ {
+ /* Error forking. */
+ close(p_to_c[0]);
+ close(c_to_p[1]);
+ goto error_ret;
+ }
+
+ if (proc_id == 0)
+ {
+ /* The 'sandbox' process started. */
+ char toolpath[FN_REFLEN];
+ size_t plugin_dir_len= strlen(opt_plugin_dir);
+
+ PAM_DEBUG((stderr, "PAM: Child process prepares pipes.\n"));
+
+ if (close(p_to_c[1]) < 0 ||
+ close(c_to_p[0]) < 0 ||
+ dup2(p_to_c[0], 0) < 0 || /* Parent's pipe to STDIN. */
+ dup2(c_to_p[1], 1) < 0) /* Sandbox's pipe to STDOUT. */
+ {
+ exit(-1);
+ }
+
+ PAM_DEBUG((stderr, "PAM: check tool directory: %s, %s.\n",
+ opt_plugin_dir, tool_name));
+ if (plugin_dir_len + tool_name_len + 2 > sizeof(toolpath))
+ {
+ /* Tool path too long. */
+ exit(-1);
+ }
+
+ memcpy(toolpath, opt_plugin_dir, plugin_dir_len);
+ if (plugin_dir_len && toolpath[plugin_dir_len-1] != FN_LIBCHAR)
+ toolpath[plugin_dir_len++]= FN_LIBCHAR;
+ memcpy(toolpath+plugin_dir_len, tool_name, tool_name_len+1);
+
+ PAM_DEBUG((stderr, "PAM: execute pam sandbox [%s].\n", toolpath));
+ (void) execl(toolpath, toolpath, NULL);
+ PAM_DEBUG((stderr, "PAM: exec() failed.\n"));
+ my_printf_error(1, "PAM: Cannot execute %s (errno: %M)", ME_ERROR_LOG_ONLY,
+ toolpath, errno);
+ exit(-1);
+ }
+
+ /* Parent process continues. */
+
+ PAM_DEBUG((stderr, "PAM: parent continues.\n"));
+ if (close(p_to_c[0]) < 0 ||
+ close(c_to_p[1]) < 0)
+ goto error_ret;
+
+ /* no user name yet ? read the client handshake packet with the user name */
+ if (info->user_name == 0)
+ {
+ if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
+ return CR_ERROR;
+ }
+ else
+ pkt= NULL;
+
+ PAM_DEBUG((stderr, "PAM: parent sends user data [%s], [%s].\n",
+ info->user_name, info->auth_string));
+
+#ifndef DBUG_OFF
+ field= pam_debug ? 1 : 0;
+#else
+ field= 0;
+#endif
+ field|= winbind_hack ? 2 : 0;
+
+ if (write(p_to_c[1], &field, 1) != 1 ||
+ write_string(p_to_c[1], (const uchar *) info->user_name,
+ info->user_name_length) ||
+ write_string(p_to_c[1], (const uchar *) info->auth_string,
+ info->auth_string_length))
+ goto error_ret;
+
+ for (;;)
+ {
+ PAM_DEBUG((stderr, "PAM: listening to the sandbox.\n"));
+ if (read(c_to_p[0], &field, 1) < 1)
+ {
+ PAM_DEBUG((stderr, "PAM: read failed.\n"));
+ goto error_ret;
+ }
+
+ if (field == AP_EOF)
+ {
+ PAM_DEBUG((stderr, "PAM: auth OK returned.\n"));
+ break;
+ }
+
+ switch (field)
+ {
+ case AP_AUTHENTICATED_AS:
+ PAM_DEBUG((stderr, "PAM: reading authenticated_as string.\n"));
+ if (read_string(c_to_p[0], info->authenticated_as,
+ sizeof(info->authenticated_as) - 1) < 0)
+ goto error_ret;
+ break;
+
+ case AP_CONV:
+ {
+ unsigned char buf[10240];
+ int buf_len;
+
+ PAM_DEBUG((stderr, "PAM: getting CONV string.\n"));
+ if ((buf_len= read_string(c_to_p[0], (char *) buf, sizeof(buf))) < 0)
+ goto error_ret;
+
+ if (!pkt || !*pkt || (buf[0] >> 1) != 2)
+ {
+ PAM_DEBUG((stderr, "PAM: sending CONV string.\n"));
+ if (vio->write_packet(vio, buf, buf_len))
+ goto error_ret;
+
+ PAM_DEBUG((stderr, "PAM: reading CONV answer.\n"));
+ if ((pkt_len= vio->read_packet(vio, &pkt)) < 0)
+ goto error_ret;
+ }
+
+ PAM_DEBUG((stderr, "PAM: answering CONV.\n"));
+ if (write_string(p_to_c[1], pkt, pkt_len))
+ goto error_ret;
+
+ pkt= NULL;
+ }
+ break;
+
+ default:
+ PAM_DEBUG((stderr, "PAM: unknown sandbox field.\n"));
+ goto error_ret;
+ }
+ }
+ result= CR_OK;
+
+error_ret:
+ close(p_to_c[1]);
+ close(c_to_p[0]);
+ while (waitpid(proc_id, NULL, WNOHANG) != (int) proc_id)
+ {
+ if (n_sleep++ == sleep_limit)
+ {
+ /*
+ The auth_pam_tool application doesn't terminate.
+ Means something wrong happened there like pam_xxx.so hanged.
+ */
+ kill(proc_id, SIGKILL);
+ sleep_time= 1000000; /* 1 second wait should be enough. */
+ PAM_DEBUG((stderr, "PAM: auth_pam_tool doesn't terminate,"
+ " have to kill it.\n"));
+ }
+ else if (n_sleep > sleep_limit)
+ break;
+ usleep(sleep_time);
+ sleep_time*= 10;
+ }
+
+ PAM_DEBUG((stderr, "PAM: auth result %d.\n", result));
+ return result;
+}
+
+
+#include "auth_pam_common.c"
+
+
+static int init(void *p __attribute__((unused)))
+{
+ if (use_cleartext_plugin)
+ info.client_auth_plugin= "mysql_clear_password";
+ if (!(opt_plugin_dir= dlsym(RTLD_DEFAULT, "opt_plugin_dir")))
+ return 1;
+ return 0;
+}
+
+maria_declare_plugin(pam)
+{
+ MYSQL_AUTHENTICATION_PLUGIN,
+ &info,
+ "pam",
+ "MariaDB Corp",
+ "PAM based authentication",
+ PLUGIN_LICENSE_GPL,
+ init,
+ NULL,
+ 0x0200,
+ NULL,
+ vars,
+ "2.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
diff --git a/plugin/auth_pam/auth_pam_base.c b/plugin/auth_pam/auth_pam_base.c
new file mode 100644
index 00000000..1e8f4a08
--- /dev/null
+++ b/plugin/auth_pam/auth_pam_base.c
@@ -0,0 +1,179 @@
+/*
+ Copyright (c) 2011, 2018 MariaDB Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
+
+/*
+ This file contains code to interact with the PAM module.
+ To be included into auth_pam_tool.c and auth_pam_v2.c,
+
+ Before the #include these sould be defined:
+
+ struct param {
+ unsigned char buf[10240], *ptr;
+ MYSQL_PLUGIN_VIO *vio;
+ ... other arbitrary fields allowed.
+ };
+ static int write_packet(struct param *param, const unsigned char *buf,
+ int buf_len)
+ static int read_packet(struct param *param, unsigned char **pkt)
+*/
+
+#include <config_auth_pam.h>
+#include <stdio.h>
+#include <string.h>
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+
+/* It least solaris doesn't have strndup */
+
+#ifndef HAVE_STRNDUP
+char *strndup(const char *from, size_t length)
+{
+ char *ptr;
+ size_t max_length= strlen(from);
+ if (length > max_length)
+ length= max_length;
+ if ((ptr= (char*) malloc(length+1)) != 0)
+ {
+ memcpy((char*) ptr, (char*) from, length);
+ ptr[length]=0;
+ }
+ return ptr;
+}
+#endif
+
+#ifndef DBUG_OFF
+static char pam_debug = 0;
+#define PAM_DEBUG(X) do { if (pam_debug) { fprintf X; } } while(0)
+#else
+#define PAM_DEBUG(X) /* no-op */
+#endif
+
+static char winbind_hack = 0;
+
+static int conv(int n, const struct pam_message **msg,
+ struct pam_response **resp, void *data)
+{
+ struct param *param = (struct param *)data;
+ unsigned char *end = param->buf + sizeof(param->buf) - 1;
+ int i;
+
+ *resp = 0;
+
+ for (i = 0; i < n; i++)
+ {
+ /* if there's a message - append it to the buffer */
+ if (msg[i]->msg)
+ {
+ int len = strlen(msg[i]->msg);
+ if (len > end - param->ptr)
+ len = end - param->ptr;
+ if (len > 0)
+ {
+ memcpy(param->ptr, msg[i]->msg, len);
+ param->ptr+= len;
+ *(param->ptr)++ = '\n';
+ }
+ }
+ /* if the message style is *_PROMPT_*, meaning PAM asks a question,
+ send the accumulated text to the client, read the reply */
+ if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF ||
+ msg[i]->msg_style == PAM_PROMPT_ECHO_ON)
+ {
+ int pkt_len;
+ unsigned char *pkt;
+
+ /* allocate the response array.
+ freeing it is the responsibility of the caller */
+ if (*resp == 0)
+ {
+ *resp = calloc(sizeof(struct pam_response), n);
+ if (*resp == 0)
+ return PAM_BUF_ERR;
+ }
+
+ /* dialog plugin interprets the first byte of the packet
+ as the magic number.
+ 2 means "read the input with the echo enabled"
+ 4 means "password-like input, echo disabled"
+ C'est la vie. */
+ param->buf[0] = msg[i]->msg_style == PAM_PROMPT_ECHO_ON ? 2 : 4;
+ PAM_DEBUG((stderr, "PAM: conv: send(%.*s)\n",
+ (int)(param->ptr - param->buf - 1), param->buf));
+ pkt_len= roundtrip(param, param->buf, param->ptr - param->buf - 1, &pkt);
+ if (pkt_len < 0)
+ return PAM_CONV_ERR;
+
+ PAM_DEBUG((stderr, "PAM: conv: recv(%.*s)\n", pkt_len, pkt));
+ /* allocate and copy the reply to the response array */
+ if (!((*resp)[i].resp= strndup((char*) pkt, pkt_len)))
+ return PAM_CONV_ERR;
+ param->ptr = param->buf + 1;
+ }
+ }
+ return PAM_SUCCESS;
+}
+
+#define DO(X) if ((status = (X)) != PAM_SUCCESS) goto end
+
+#if defined(SOLARIS) || defined(__sun)
+typedef void** pam_get_item_3_arg;
+#else
+typedef const void** pam_get_item_3_arg;
+#endif
+
+static int pam_auth_base(struct param *param, MYSQL_SERVER_AUTH_INFO *info)
+{
+ pam_handle_t *pamh = NULL;
+ int status;
+ const char *new_username= NULL;
+ /* The following is written in such a way to make also solaris happy */
+ struct pam_conv pam_start_arg = { &conv, (char*) param };
+
+ /*
+ get the service name, as specified in
+
+ CREATE USER ... IDENTIFIED WITH pam AS "service"
+ */
+ const char *service = info->auth_string && info->auth_string[0]
+ ? info->auth_string : "mysql";
+
+ param->ptr = param->buf + 1;
+
+ PAM_DEBUG((stderr, "PAM: pam_start(%s, %s)\n", service, info->user_name));
+ DO( pam_start(service, info->user_name, &pam_start_arg, &pamh) );
+
+ PAM_DEBUG((stderr, "PAM: pam_authenticate(0)\n"));
+ DO( pam_authenticate (pamh, 0) );
+
+ PAM_DEBUG((stderr, "PAM: pam_acct_mgmt(0)\n"));
+ DO( pam_acct_mgmt(pamh, 0) );
+
+ PAM_DEBUG((stderr, "PAM: pam_get_item(PAM_USER)\n"));
+ DO( pam_get_item(pamh, PAM_USER, (pam_get_item_3_arg) &new_username) );
+
+ if (new_username &&
+ (winbind_hack ? strcasecmp : strcmp)(new_username, info->user_name))
+ strncpy(info->authenticated_as, new_username,
+ sizeof(info->authenticated_as));
+ info->authenticated_as[sizeof(info->authenticated_as)-1]= 0;
+
+end:
+ PAM_DEBUG((stderr, "PAM: status = %d (%s) user = %s\n",
+ status, pam_strerror(pamh, status), info->authenticated_as));
+ pam_end(pamh, status);
+ return status == PAM_SUCCESS ? CR_OK : CR_ERROR;
+}
+
diff --git a/plugin/auth_pam/auth_pam_common.c b/plugin/auth_pam/auth_pam_common.c
new file mode 100644
index 00000000..ef8f0f65
--- /dev/null
+++ b/plugin/auth_pam/auth_pam_common.c
@@ -0,0 +1,56 @@
+/*
+ Copyright (c) 2011, 2018 MariaDB Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
+
+/*
+ In this file we gather the plugin interface definitions
+ that are same in all the PAM plugin versions.
+ To be included into auth_pam.c and auth_pam_v1.c.
+*/
+
+static struct st_mysql_auth info =
+{
+ MYSQL_AUTHENTICATION_INTERFACE_VERSION,
+ "dialog",
+ pam_auth,
+ NULL, NULL /* no PASSWORD() */
+};
+
+static char use_cleartext_plugin;
+static MYSQL_SYSVAR_BOOL(use_cleartext_plugin, use_cleartext_plugin,
+ PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
+ "Use mysql_cleartext_plugin on the client side instead of the dialog "
+ "plugin. This may be needed for compatibility reasons, but it only "
+ "supports simple PAM policies that don't require anything besides "
+ "a password", NULL, NULL, 0);
+
+static MYSQL_SYSVAR_BOOL(winbind_workaround, winbind_hack, PLUGIN_VAR_OPCMDARG,
+ "Compare usernames case insensitively to work around pam_winbind "
+ "unconditional username lowercasing", NULL, NULL, 0);
+
+#ifndef DBUG_OFF
+static MYSQL_SYSVAR_BOOL(debug, pam_debug, PLUGIN_VAR_OPCMDARG,
+ "Log all PAM activity", NULL, NULL, 0);
+#endif
+
+
+static struct st_mysql_sys_var* vars[] = {
+ MYSQL_SYSVAR(use_cleartext_plugin),
+ MYSQL_SYSVAR(winbind_workaround),
+#ifndef DBUG_OFF
+ MYSQL_SYSVAR(debug),
+#endif
+ NULL
+};
diff --git a/plugin/auth_pam/auth_pam_tool.c b/plugin/auth_pam/auth_pam_tool.c
new file mode 100644
index 00000000..225f35a6
--- /dev/null
+++ b/plugin/auth_pam/auth_pam_tool.c
@@ -0,0 +1,120 @@
+/*
+ Copyright (c) 2011, 2018 MariaDB Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <mysql/plugin_auth_common.h>
+
+struct param {
+ unsigned char buf[10240], *ptr;
+};
+
+
+#include "auth_pam_tool.h"
+
+
+static int roundtrip(struct param *param, const unsigned char *buf,
+ int buf_len, unsigned char **pkt)
+{
+ unsigned char b= AP_CONV;
+ if (write(1, &b, 1) < 1 || write_string(1, buf, buf_len))
+ return -1;
+ *pkt= (unsigned char *) param->buf;
+ return read_string(0, (char *) param->buf, (int) sizeof(param->buf));
+}
+
+typedef struct st_mysql_server_auth_info
+{
+ /**
+ User name as sent by the client and shown in USER().
+ NULL if the client packet with the user name was not received yet.
+ */
+ char *user_name;
+
+ /**
+ A corresponding column value from the mysql.user table for the
+ matching account name
+ */
+ char *auth_string;
+
+ /**
+ Matching account name as found in the mysql.user table.
+ A plugin can override it with another name that will be
+ used by MySQL for authorization, and shown in CURRENT_USER()
+ */
+ char authenticated_as[MYSQL_USERNAME_LENGTH+1];
+} MYSQL_SERVER_AUTH_INFO;
+
+
+#include "auth_pam_base.c"
+
+
+int main(int argc __attribute__((unused)), char **argv __attribute__((unused)))
+{
+ struct param param;
+ MYSQL_SERVER_AUTH_INFO info;
+ unsigned char field;
+ int res;
+ char a_buf[MYSQL_USERNAME_LENGTH + 1 + 1024];
+
+ if ((res= setreuid(0, 0)))
+ fprintf(stderr, "Got error %d from setreuid()\n", (int) errno);
+
+ if (read(0, &field, 1) < 1)
+ return -1;
+#ifndef DBUG_OFF
+ pam_debug= field & 1;
+#endif
+ winbind_hack= field & 2;
+
+ PAM_DEBUG((stderr, "PAM: sandbox started [%s].\n", argv[0]));
+
+ info.user_name= a_buf;
+ if ((res= read_string(0, info.user_name, sizeof(a_buf))) < 0)
+ return -1;
+ PAM_DEBUG((stderr, "PAM: sandbox username [%s].\n", info.user_name));
+
+ info.auth_string= info.user_name + res + 1;
+ if (read_string(0, info.auth_string, sizeof(a_buf) - 1 - res) < 0)
+ return -1;
+
+ PAM_DEBUG((stderr, "PAM: sandbox auth string [%s].\n", info.auth_string));
+
+ if ((res= pam_auth_base(&param, &info)) != CR_OK)
+ {
+ PAM_DEBUG((stderr, "PAM: auth failed, sandbox closed.\n"));
+ return -1;
+ }
+
+ if (info.authenticated_as[0])
+ {
+ PAM_DEBUG((stderr, "PAM: send authenticated_as field.\n"));
+ field= AP_AUTHENTICATED_AS;
+ if (write(1, &field, 1) < 1 ||
+ write_string(1, (unsigned char *) info.authenticated_as,
+ strlen(info.authenticated_as)))
+ return -1;
+ }
+
+ PAM_DEBUG((stderr, "PAM: send OK result.\n"));
+ field= AP_EOF;
+ if (write(1, &field, 1) != 1)
+ return -1;
+
+ PAM_DEBUG((stderr, "PAM: sandbox closed.\n"));
+ return 0;
+}
diff --git a/plugin/auth_pam/auth_pam_tool.h b/plugin/auth_pam/auth_pam_tool.h
new file mode 100644
index 00000000..60ae016d
--- /dev/null
+++ b/plugin/auth_pam/auth_pam_tool.h
@@ -0,0 +1,81 @@
+/*
+ Copyright (c) 2011, 2018 MariaDB Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
+
+/*
+ This file contains definitions and functions for
+ the interface between the auth_pam.so (PAM plugin version 2)
+ and the auth_pam_tool executable.
+ To be included both in auth_pam.c and auth_pam_tool.c.
+*/
+
+#define AP_AUTHENTICATED_AS 'A'
+#define AP_CONV 'C'
+#define AP_EOF 'E'
+
+
+static int read_length(int file)
+{
+ unsigned char hdr[2];
+
+ if (read(file, hdr, 2) < 2)
+ return -1;
+
+ return (((int) hdr[0]) << 8) + (int) hdr[1];
+}
+
+
+static void store_length(int len, unsigned char *p_len)
+{
+ p_len[0]= (unsigned char) ((len >> 8) & 0xFF);
+ p_len[1]= (unsigned char) (len & 0xFF);
+}
+
+
+/*
+ Returns the length of the string read,
+ or -1 on error.
+*/
+
+static int read_string(int file, char *s, int s_size)
+{
+ int len;
+
+ len= read_length(file);
+
+ if (len < 0 || len > s_size-1 ||
+ read(file, s, len) < len)
+ return -1;
+
+ s[len]= 0;
+
+ return len;
+}
+
+
+/*
+ Returns 0 on success.
+*/
+
+static int write_string(int file, const unsigned char *s, int s_len)
+{
+ unsigned char hdr[2];
+ store_length(s_len, hdr);
+ return write(file, hdr, 2) < 2 ||
+ write(file, s, s_len) < s_len;
+}
+
+
+#define MAX_PAM_SERVICE_NAME 1024
diff --git a/plugin/auth_pam/auth_pam_v1.c b/plugin/auth_pam/auth_pam_v1.c
new file mode 100644
index 00000000..a38ef8f5
--- /dev/null
+++ b/plugin/auth_pam/auth_pam_v1.c
@@ -0,0 +1,86 @@
+/*
+ Copyright (c) 2011, 2018 MariaDB Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
+
+#include <mysql/plugin_auth.h>
+
+struct param {
+ unsigned char buf[10240], *ptr, *cached;
+ int cached_len;
+ MYSQL_PLUGIN_VIO *vio;
+};
+
+static int roundtrip(struct param *param, const unsigned char *buf,
+ int buf_len, unsigned char **pkt)
+{
+ if (param->cached && *param->cached && (buf[0] >> 1) == 2)
+ {
+ *pkt= param->cached;
+ param->cached= NULL;
+ return param->cached_len;
+ }
+ param->cached= NULL;
+ if (param->vio->write_packet(param->vio, buf, buf_len))
+ return -1;
+ return param->vio->read_packet(param->vio, pkt);
+}
+
+#include "auth_pam_base.c"
+
+static int pam_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
+{
+ struct param param;
+ param.vio = vio;
+
+ /* no user name yet ? read the client handshake packet with the user name */
+ if (info->user_name == 0)
+ {
+ if ((param.cached_len= vio->read_packet(vio, &param.cached)) < 0)
+ return CR_ERROR;
+ }
+ else
+ param.cached= NULL;
+
+ return pam_auth_base(&param, info);
+}
+
+
+#include "auth_pam_common.c"
+
+
+static int init(void *p __attribute__((unused)))
+{
+ if (use_cleartext_plugin)
+ info.client_auth_plugin= "mysql_clear_password";
+ return 0;
+}
+
+maria_declare_plugin(pam)
+{
+ MYSQL_AUTHENTICATION_PLUGIN,
+ &info,
+ "pam",
+ "Sergei Golubchik",
+ "PAM based authentication",
+ PLUGIN_LICENSE_GPL,
+ init,
+ NULL,
+ 0x0100,
+ NULL,
+ vars,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
diff --git a/plugin/auth_pam/config.h.cmake b/plugin/auth_pam/config.h.cmake
new file mode 100644
index 00000000..2a60e99d
--- /dev/null
+++ b/plugin/auth_pam/config.h.cmake
@@ -0,0 +1,5 @@
+#cmakedefine HAVE_POSIX_GETGROUPLIST 1
+#cmakedefine HAVE_PAM_SYSLOG 1
+#cmakedefine HAVE_PAM_EXT_H 1
+#cmakedefine HAVE_PAM_APPL_H 1
+#cmakedefine HAVE_STRNDUP 1
diff --git a/plugin/auth_pam/mapper/pam_user_map.c b/plugin/auth_pam/mapper/pam_user_map.c
new file mode 100644
index 00000000..fa8d9ae0
--- /dev/null
+++ b/plugin/auth_pam/mapper/pam_user_map.c
@@ -0,0 +1,277 @@
+/*
+ Pam module to change user names arbitrarily in the pam stack.
+
+ Compile as
+
+ gcc pam_user_map.c -shared -lpam -fPIC -o pam_user_map.so
+
+ Install as appropriate (for example, in /lib/security/).
+ Add to your /etc/pam.d/mysql (preferably, at the end) this line:
+=========================================================
+auth required pam_user_map.so
+=========================================================
+
+ And create /etc/security/user_map.conf with the desired mapping
+ in the format: orig_user_name: mapped_user_name
+ @user's_group_name: mapped_user_name
+=========================================================
+#comments and empty lines are ignored
+john: jack
+bob: admin
+top: accounting
+@group_ro: readonly
+=========================================================
+
+If something doesn't work as expected you can get verbose
+comments with the 'debug' option like this
+=========================================================
+auth required pam_user_map.so debug
+=========================================================
+These comments are written to the syslog as 'authpriv.debug'
+and usually end up in /var/log/secure file.
+*/
+
+#include <config_auth_pam.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <syslog.h>
+#include <grp.h>
+#include <pwd.h>
+
+#ifdef HAVE_PAM_EXT_H
+#include <security/pam_ext.h>
+#endif
+
+#ifdef HAVE_PAM_APPL_H
+#include <unistd.h>
+#include <security/pam_appl.h>
+#endif
+
+#include <security/pam_modules.h>
+
+#ifndef HAVE_PAM_SYSLOG
+#include <stdarg.h>
+static void
+pam_syslog (const pam_handle_t *pamh, int priority,
+ const char *fmt, ...)
+{
+ va_list args;
+ va_start (args, fmt);
+ vsyslog (priority, fmt, args);
+ va_end (args);
+}
+#endif
+
+#define FILENAME "/etc/security/user_map.conf"
+#define skip(what) while (*s && (what)) s++
+#define SYSLOG_DEBUG if (mode_debug) pam_syslog
+
+#define GROUP_BUFFER_SIZE 100
+static const char debug_keyword[]= "debug";
+
+#ifdef HAVE_POSIX_GETGROUPLIST
+typedef gid_t my_gid_t;
+#else
+typedef int my_gid_t;
+#endif
+
+static int populate_user_groups(const char *user, my_gid_t **groups)
+{
+ my_gid_t user_group_id;
+ my_gid_t *loc_groups= *groups;
+ int ng;
+
+ {
+ struct passwd *pw= getpwnam(user);
+ if (!pw)
+ return 0;
+ user_group_id= pw->pw_gid;
+ }
+
+ ng= GROUP_BUFFER_SIZE;
+ if (getgrouplist(user, user_group_id, loc_groups, &ng) < 0)
+ {
+ /* The rare case when the user is present in more than */
+ /* GROUP_BUFFER_SIZE groups. */
+ loc_groups= (my_gid_t *) malloc(ng * sizeof (my_gid_t));
+
+ if (!loc_groups)
+ return 0;
+
+ (void) getgrouplist(user, user_group_id, loc_groups, &ng);
+ *groups= (my_gid_t*)loc_groups;
+ }
+
+ return ng;
+}
+
+
+static int user_in_group(const my_gid_t *user_groups, int ng,const char *group)
+{
+ my_gid_t group_id;
+ const my_gid_t *groups_end = user_groups + ng;
+
+ {
+ struct group *g= getgrnam(group);
+ if (!g)
+ return 0;
+ group_id= g->gr_gid;
+ }
+
+ for (; user_groups < groups_end; user_groups++)
+ {
+ if (*user_groups == group_id)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void print_groups(pam_handle_t *pamh, const my_gid_t *user_groups, int ng)
+{
+ char buf[256];
+ char *c_buf= buf, *buf_end= buf+sizeof(buf)-2;
+ struct group *gr;
+ int cg;
+
+ for (cg=0; cg < ng; cg++)
+ {
+ char *c;
+ if (c_buf == buf_end)
+ break;
+ *(c_buf++)= ',';
+ if (!(gr= getgrgid(user_groups[cg])) ||
+ !(c= gr->gr_name))
+ continue;
+ while (*c)
+ {
+ if (c_buf == buf_end)
+ break;
+ *(c_buf++)= *(c++);
+ }
+ }
+ c_buf[0]= c_buf[1]= 0;
+ pam_syslog(pamh, LOG_DEBUG, "User belongs to %d %s [%s].\n",
+ ng, (ng == 1) ? "group" : "groups", buf+1);
+}
+
+int pam_sm_authenticate(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+ int mode_debug= 0;
+ int pam_err, line= 0;
+ const char *username;
+ char buf[256];
+ FILE *f;
+ my_gid_t group_buffer[GROUP_BUFFER_SIZE];
+ my_gid_t *groups= group_buffer;
+ int n_groups= -1;
+
+ for (; argc > 0; argc--)
+ {
+ if (strcasecmp(argv[argc-1], debug_keyword) == 0)
+ mode_debug= 1;
+ }
+
+ SYSLOG_DEBUG(pamh, LOG_DEBUG, "Opening file '%s'.\n", FILENAME);
+
+ f= fopen(FILENAME, "r");
+ if (f == NULL)
+ {
+ pam_syslog(pamh, LOG_ERR, "Cannot open '%s'\n", FILENAME);
+ return PAM_SYSTEM_ERR;
+ }
+
+ pam_err = pam_get_item(pamh, PAM_USER, (const void**)&username);
+ if (pam_err != PAM_SUCCESS)
+ {
+ pam_syslog(pamh, LOG_ERR, "Cannot get username.\n");
+ goto ret;
+ }
+
+ SYSLOG_DEBUG(pamh, LOG_DEBUG, "Incoming username '%s'.\n", username);
+
+ while (fgets(buf, sizeof(buf), f) != NULL)
+ {
+ char *s= buf, *from, *to, *end_from, *end_to;
+ int check_group;
+ int cmp_result;
+
+ line++;
+
+ skip(isspace(*s));
+ if (*s == '#' || *s == 0) continue;
+ if ((check_group= *s == '@'))
+ {
+ if (n_groups < 0)
+ {
+ n_groups= populate_user_groups(username, &groups);
+ if (mode_debug)
+ print_groups(pamh, groups, n_groups);
+ }
+ s++;
+ }
+ from= s;
+ skip(isalnum(*s) || (*s == '_') || (*s == '.') || (*s == '-') ||
+ (*s == '$') || (*s == '\\') || (*s == '/'));
+ end_from= s;
+ skip(isspace(*s));
+ if (end_from == from || *s++ != ':') goto syntax_error;
+ skip(isspace(*s));
+ to= s;
+ skip(isalnum(*s) || (*s == '_') || (*s == '.') || (*s == '-') ||
+ (*s == '$'));
+ end_to= s;
+ if (end_to == to) goto syntax_error;
+
+ *end_from= *end_to= 0;
+
+ if (check_group)
+ {
+ cmp_result= user_in_group(groups, n_groups, from);
+ SYSLOG_DEBUG(pamh, LOG_DEBUG, "Check if user is in group '%s': %s\n",
+ from, cmp_result ? "YES":"NO");
+ }
+ else
+ {
+ cmp_result= (strcmp(username, from) == 0);
+ SYSLOG_DEBUG(pamh, LOG_DEBUG, "Check if username '%s': %s\n",
+ from, cmp_result ? "YES":"NO");
+ }
+ if (cmp_result)
+ {
+ pam_err= pam_set_item(pamh, PAM_USER, to);
+ SYSLOG_DEBUG(pamh, LOG_DEBUG,
+ (pam_err == PAM_SUCCESS) ? "User mapped as '%s'\n" :
+ "Couldn't map as '%s'\n", to);
+ goto ret;
+ }
+ }
+
+ SYSLOG_DEBUG(pamh, LOG_DEBUG, "User not found in the list.\n");
+ pam_err= PAM_AUTH_ERR;
+ goto ret;
+
+syntax_error:
+ pam_syslog(pamh, LOG_ERR, "Syntax error at %s:%d", FILENAME, line);
+ pam_err= PAM_SYSTEM_ERR;
+ret:
+ if (groups != group_buffer)
+ free(groups);
+
+ fclose(f);
+
+ return pam_err;
+}
+
+
+int pam_sm_setcred(pam_handle_t *pamh, int flags,
+ int argc, const char *argv[])
+{
+
+ return PAM_SUCCESS;
+}
+
diff --git a/plugin/auth_pam/mapper/user_map.conf b/plugin/auth_pam/mapper/user_map.conf
new file mode 100644
index 00000000..4af8fb0f
--- /dev/null
+++ b/plugin/auth_pam/mapper/user_map.conf
@@ -0,0 +1,13 @@
+#
+# Configuration file for pam_user_map.so
+#
+# defines mapping in the form
+#
+# orig_user_name: mapped_user_name
+#
+# or (to map all users in a specific group)
+#
+# @group_name: mapped_user_name
+#
+# comments and empty lines are ignored
+#
diff --git a/plugin/auth_pam/testing/CMakeLists.txt b/plugin/auth_pam/testing/CMakeLists.txt
new file mode 100644
index 00000000..151823b9
--- /dev/null
+++ b/plugin/auth_pam/testing/CMakeLists.txt
@@ -0,0 +1,15 @@
+# gcc pam_mariadb_mtr.c -shared -lpam -fPIC -o pam_mariadb_mtr.so
+
+ADD_LIBRARY(pam_mariadb_mtr MODULE pam_mariadb_mtr.c)
+SET_TARGET_PROPERTIES (pam_mariadb_mtr PROPERTIES PREFIX "")
+TARGET_LINK_LIBRARIES(pam_mariadb_mtr pam)
+
+IF(CMAKE_C_COMPILER_ID MATCHES "Clang")
+ SET_SOURCE_FILES_PROPERTIES(
+ pam_mariadb_mtr.c
+ PROPERTY COMPILE_FLAGS "-Wno-incompatible-pointer-types-discards-qualifiers")
+ENDIF()
+
+SET(dest DESTINATION "${INSTALL_MYSQLTESTDIR}/suite/plugins/pam" COMPONENT Test)
+INSTALL(TARGETS pam_mariadb_mtr ${dest})
+INSTALL(FILES mariadb_mtr.conf RENAME mariadb_mtr ${dest})
diff --git a/plugin/auth_pam/testing/mariadb_mtr.conf b/plugin/auth_pam/testing/mariadb_mtr.conf
new file mode 100644
index 00000000..241afb43
--- /dev/null
+++ b/plugin/auth_pam/testing/mariadb_mtr.conf
@@ -0,0 +1,4 @@
+# Put it in /etc/pam.d/mariadb_mtr
+
+auth required pam_mariadb_mtr.so pam_test
+account required pam_permit.so
diff --git a/plugin/auth_pam/testing/pam_mariadb_mtr.c b/plugin/auth_pam/testing/pam_mariadb_mtr.c
new file mode 100644
index 00000000..f61a8da7
--- /dev/null
+++ b/plugin/auth_pam/testing/pam_mariadb_mtr.c
@@ -0,0 +1,83 @@
+/*
+ This code is in the public domain and has no copyright.
+
+ Pam module to test pam authentication plugin. Used in pam tests.
+ Linux only.
+
+ Install as appropriate (for example, in /lib/security/).
+ see also mariadb_mtr.conf
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <security/pam_modules.h>
+#include <security/pam_appl.h>
+
+#define N 3
+
+int pam_sm_authenticate(pam_handle_t *pamh, int flags __attribute__((unused)),
+ int argc, const char *argv[])
+{
+ struct pam_conv *conv;
+ struct pam_response *resp = 0;
+ int pam_err, retval = PAM_SYSTEM_ERR;
+ struct pam_message msg[N] = {
+ { PAM_TEXT_INFO, (char*)"Challenge input first." },
+ { PAM_PROMPT_ECHO_OFF, (char*)"Enter:" },
+ { PAM_ERROR_MSG, (char*)"Now, the magic number!" }
+ };
+ const struct pam_message *msgp[N] = { msg, msg+1, msg+2 };
+ char *r1 = 0, *r2 = 0;
+
+ pam_err = pam_get_item(pamh, PAM_CONV, (const void **)&conv);
+ if (pam_err != PAM_SUCCESS)
+ goto ret;
+
+ pam_err = (*conv->conv)(N, msgp, &resp, conv->appdata_ptr);
+
+ if (pam_err != PAM_SUCCESS || !resp || !((r1= resp[1].resp)))
+ goto ret;
+
+ if (strcmp(r1, "cleartext good") == 0)
+ retval = PAM_SUCCESS;
+ else if (strcmp(r1, "cleartext bad") == 0)
+ retval = PAM_AUTH_ERR;
+ else
+ {
+ free(resp);
+ msg[0].msg_style = PAM_PROMPT_ECHO_ON;
+ msg[0].msg = (char*)"PIN:";
+ pam_err = (*conv->conv)(1, msgp, &resp, conv->appdata_ptr);
+
+ if (pam_err != PAM_SUCCESS || !resp || !((r2= resp[0].resp)))
+ goto ret;
+
+ /* Produce the crash for testing purposes. */
+ if (strcmp(r1, "crash pam module") == 0 && atoi(r2) == 616)
+ abort();
+
+ if (strlen(r1) == (size_t)atoi(r2) % 100)
+ retval = PAM_SUCCESS;
+ else
+ retval = PAM_AUTH_ERR;
+ }
+
+ if (argc > 0 && argv[0])
+ pam_set_item(pamh, PAM_USER, argv[0]);
+
+ret:
+ free(resp);
+ free(r1);
+ free(r2);
+ return retval;
+}
+
+int pam_sm_setcred(pam_handle_t *pamh __attribute__((unused)),
+ int flags __attribute__((unused)),
+ int argc __attribute__((unused)),
+ const char *argv[] __attribute__((unused)))
+{
+
+ return PAM_SUCCESS;
+}
+
diff --git a/plugin/auth_pipe/CMakeLists.txt b/plugin/auth_pipe/CMakeLists.txt
new file mode 100644
index 00000000..bbc44d0f
--- /dev/null
+++ b/plugin/auth_pipe/CMakeLists.txt
@@ -0,0 +1,3 @@
+IF(WIN32)
+ MYSQL_ADD_PLUGIN(auth_named_pipe auth_pipe.c)
+ENDIF()
diff --git a/plugin/auth_pipe/auth_pipe.c b/plugin/auth_pipe/auth_pipe.c
new file mode 100644
index 00000000..902add44
--- /dev/null
+++ b/plugin/auth_pipe/auth_pipe.c
@@ -0,0 +1,94 @@
+/* Copyright (C) 2015 Vladislav Vaintroub, Georg Richter and Monty Program Ab
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; version 2 of the
+ License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/**
+ @file
+
+ auth_pipe authentication plugin.
+
+ Authentication is successful if the connection is done via a named pipe
+ pipe peer name matches mysql user name
+*/
+
+#include <mysql/plugin_auth.h>
+#include <string.h>
+#include <lmcons.h>
+
+
+/**
+ This authentication callback obtains user name using named pipe impersonation
+*/
+static int pipe_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
+{
+ unsigned char *pkt;
+ MYSQL_PLUGIN_VIO_INFO vio_info;
+ char username[UNLEN + 1];
+ DWORD username_length;
+ int ret;
+
+ /* no user name yet ? read the client handshake packet with the user name */
+ if (info->user_name == 0)
+ {
+ if (vio->read_packet(vio, &pkt) < 0)
+ return CR_ERROR;
+ }
+ info->password_used= PASSWORD_USED_NO_MENTION;
+ vio->info(vio, &vio_info);
+ if (vio_info.protocol != MYSQL_VIO_PIPE)
+ return CR_ERROR;
+
+ /* Impersonate the named pipe peer, and retrieve the user name */
+ if (!ImpersonateNamedPipeClient(vio_info.handle))
+ return CR_ERROR;
+
+ username_length=UNLEN;
+ ret= CR_ERROR;
+ if (GetUserName(username, &username_length))
+ {
+ /* Always compare names case-insensitive on Windows.*/
+ if (_stricmp(username, info->user_name) == 0)
+ ret= CR_OK;
+ }
+ RevertToSelf();
+
+ return ret;
+}
+
+static struct st_mysql_auth pipe_auth_handler=
+{
+ MYSQL_AUTHENTICATION_INTERFACE_VERSION,
+ 0,
+ pipe_auth
+};
+
+maria_declare_plugin(auth_named_pipe)
+{
+ MYSQL_AUTHENTICATION_PLUGIN,
+ &pipe_auth_handler,
+ "named_pipe",
+ "Vladislav Vaintroub, Georg Richter",
+ "Windows named pipe based authentication",
+ PLUGIN_LICENSE_GPL,
+ NULL,
+ NULL,
+ 0x0100,
+ NULL,
+ NULL,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
+
diff --git a/plugin/auth_socket/CMakeLists.txt b/plugin/auth_socket/CMakeLists.txt
new file mode 100644
index 00000000..a3f42d41
--- /dev/null
+++ b/plugin/auth_socket/CMakeLists.txt
@@ -0,0 +1,110 @@
+# Copyright (c) 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 the Free Software Foundation; version 2 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
+
+CHECK_CXX_SOURCE_COMPILES(
+"#define _GNU_SOURCE
+#include <sys/socket.h>
+int main() {
+ struct ucred cred;
+ getsockopt(0, SOL_SOCKET, SO_PEERCRED, &cred, 0);
+}" HAVE_PEERCRED)
+
+IF (HAVE_PEERCRED)
+ ADD_DEFINITIONS(-DHAVE_PEERCRED)
+ SET(ok 1)
+ELSE()
+
+# Hi, OpenBSD!
+CHECK_CXX_SOURCE_COMPILES(
+"#include <sys/types.h>
+#include <sys/socket.h>
+int main() {
+ struct sockpeercred cred;
+ getsockopt(0, SOL_SOCKET, SO_PEERCRED, &cred, 0);
+ }" HAVE_SOCKPEERCRED)
+
+IF (HAVE_SOCKPEERCRED)
+ ADD_DEFINITIONS(-DHAVE_SOCKPEERCRED)
+ SET(ok 1)
+ELSE()
+
+# FreeBSD, is that you?
+CHECK_CXX_SOURCE_COMPILES(
+"#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/ucred.h>
+int main() {
+ struct xucred cred;
+ getsockopt(0, 0, LOCAL_PEERCRED, &cred, 0);
+ }" HAVE_XUCRED)
+
+IF (HAVE_XUCRED)
+ ADD_DEFINITIONS(-DHAVE_XUCRED)
+ SET(ok 1)
+ELSE()
+
+# illumos, is that you?
+CHECK_CXX_SOURCE_COMPILES(
+"#include <ucred.h>
+int main() {
+ ucred_t *cred = NULL;
+ getpeerucred(0, &cred);
+ }" HAVE_GETPEERUCRED)
+
+# Depending on the flags set in the compilation environment, illumos will have
+# either the POSIX.1c draft 6 or POSIX.1c final implementation of getpwuid_r()
+# Check that defining _POSIX_PTHREAD_SEMANTICS provides the final standard
+# version.
+
+CHECK_CXX_SOURCE_COMPILES(
+"#define _POSIX_PTHREAD_SEMANTICS
+#include <pwd.h>
+int main() {
+ getpwuid_r(0, NULL, NULL, 0, NULL);
+ }" HAVE_GETPWUID_POSIX_FINAL)
+
+IF (HAVE_GETPEERUCRED AND HAVE_GETPWUID_POSIX_FINAL)
+ ADD_DEFINITIONS(-DHAVE_GETPEERUCRED)
+ ADD_DEFINITIONS(-D_POSIX_PTHREAD_SEMANTICS)
+ SET(ok 1)
+ELSE()
+
+# AIX also!
+CHECK_CXX_SOURCE_COMPILES(
+"#include <sys/socket.h>
+int main() {
+ struct peercred_struct cred;
+ getsockopt(0, SOL_SOCKET, SO_PEERID, &cred, 0);
+ }" HAVE_PEERCRED_STRUCT)
+
+IF (HAVE_PEERCRED_STRUCT)
+ ADD_DEFINITIONS(-DHAVE_PEERCRED_STRUCT)
+ SET(ok 1)
+ELSE()
+
+# Who else? Anyone?
+# C'mon, show your creativity, be different! ifdef's are fun, aren't they?
+
+ENDIF()
+ENDIF()
+ENDIF()
+ENDIF()
+ENDIF()
+
+IF(ok)
+ MYSQL_ADD_PLUGIN(auth_socket auth_socket.c DEFAULT)
+ENDIF()
diff --git a/plugin/auth_socket/auth_socket.c b/plugin/auth_socket/auth_socket.c
new file mode 100644
index 00000000..c20defed
--- /dev/null
+++ b/plugin/auth_socket/auth_socket.c
@@ -0,0 +1,149 @@
+/* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab
+ Copyright (c) 2010, 2011, Oracle and/or its affiliates.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; version 2 of the
+ License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/**
+ @file
+
+ auth_socket authentication plugin.
+
+ Authentication is successful if the connection is done via a unix socket and
+ the owner of the client process matches the user name that was used when
+ connecting to mysqld.
+*/
+#define _GNU_SOURCE 1 /* for struct ucred */
+
+#include <mysql/plugin_auth.h>
+#include <string.h>
+#include <pwd.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#ifdef HAVE_PEERCRED
+#define level SOL_SOCKET
+
+#elif defined HAVE_SOCKPEERCRED
+#define level SOL_SOCKET
+#define ucred sockpeercred
+
+#elif defined HAVE_XUCRED
+#include <sys/un.h>
+#include <sys/ucred.h>
+#define level 0
+#define SO_PEERCRED LOCAL_PEERCRED
+#define uid cr_uid
+#define ucred xucred
+
+#elif defined HAVE_GETPEERUCRED
+#include <ucred.h>
+
+#elif defined HAVE_PEERCRED_STRUCT
+#define level SOL_SOCKET
+#define SO_PEERCRED SO_PEERID
+#define uid euid
+#define ucred peercred_struct
+
+#else
+#error impossible
+#endif
+
+/**
+ perform the unix socket based authentication
+
+ This authentication callback performs a unix socket based authentication -
+ it gets the uid of the client process and considers the user authenticated
+ if it uses username of this uid. That is - if the user is already
+ authenticated to the OS (if she is logged in) - she can use MySQL as herself
+*/
+
+static int socket_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
+{
+ unsigned char *pkt;
+ MYSQL_PLUGIN_VIO_INFO vio_info;
+#ifdef HAVE_GETPEERUCRED
+ ucred_t *cred = NULL;
+#else
+ struct ucred cred;
+ socklen_t cred_len= sizeof(cred);
+#endif
+ struct passwd pwd_buf, *pwd;
+ char buf[1024];
+ uid_t u;
+
+ /* no user name yet ? read the client handshake packet with the user name */
+ if (info->user_name == 0)
+ {
+ if (vio->read_packet(vio, &pkt) < 0)
+ return CR_ERROR;
+ }
+
+ info->password_used= PASSWORD_USED_NO_MENTION;
+
+ vio->info(vio, &vio_info);
+ if (vio_info.protocol != MYSQL_VIO_SOCKET)
+ return CR_ERROR;
+
+ /* get the UID of the client process */
+#ifdef HAVE_GETPEERUCRED
+ if (getpeerucred(vio_info.socket, &cred) != 0)
+ return CR_ERROR;
+ u = ucred_geteuid(cred);
+ ucred_free(cred);
+#else
+ if (getsockopt(vio_info.socket, level, SO_PEERCRED, &cred, &cred_len))
+ return CR_ERROR;
+
+ if (cred_len != sizeof(cred))
+ return CR_ERROR;
+
+ u = cred.uid;
+#endif
+
+ /* and find the username for this uid */
+ getpwuid_r(u, &pwd_buf, buf, sizeof(buf), &pwd);
+ if (pwd == NULL)
+ return CR_ERROR;
+
+ /* now it's simple as that */
+ return strcmp(pwd->pw_name, info->user_name) ? CR_ERROR : CR_OK;
+}
+
+static struct st_mysql_auth socket_auth_handler=
+{
+ MYSQL_AUTHENTICATION_INTERFACE_VERSION,
+ 0,
+ socket_auth,
+ NULL, NULL /* no PASSWORD() */
+};
+
+maria_declare_plugin(auth_socket)
+{
+ MYSQL_AUTHENTICATION_PLUGIN,
+ &socket_auth_handler,
+ "unix_socket",
+ "Sergei Golubchik",
+ "Unix Socket based authentication",
+ PLUGIN_LICENSE_GPL,
+ NULL,
+ NULL,
+ 0x0100,
+ NULL,
+ NULL,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
+
diff --git a/plugin/aws_key_management/CMakeLists.txt b/plugin/aws_key_management/CMakeLists.txt
new file mode 100644
index 00000000..3c6ca018
--- /dev/null
+++ b/plugin/aws_key_management/CMakeLists.txt
@@ -0,0 +1,17 @@
+INCLUDE(aws_sdk)
+CHECK_AWS_SDK(HAVE_AWS_SDK REASON)
+IF(NOT HAVE_AWS_SDK)
+ MESSAGE_ONCE(AWS_KEY_MANAGEMENT_NO_AWS_SDK "Can't build aws_key_management - AWS SDK not available (${REASON})")
+ ADD_FEATURE_INFO(AWS_KEY_MANAGEMENT "OFF" "AWS Encryption Key Management Plugin")
+ RETURN()
+ENDIF()
+
+MYSQL_ADD_PLUGIN(aws_key_management
+ aws_key_management_plugin.cc
+ COMPONENT aws-key-management)
+
+IF(TARGET aws_key_management)
+ USE_AWS_SDK_LIBS(aws_key_management kms)
+ENDIF()
+
+ADD_FEATURE_INFO(AWS_KEY_MANAGEMENT "ON" "AWS Encryption Key Management Plugin")
diff --git a/plugin/aws_key_management/aws_key_management_plugin.cc b/plugin/aws_key_management/aws_key_management_plugin.cc
new file mode 100644
index 00000000..7740c2ea
--- /dev/null
+++ b/plugin/aws_key_management/aws_key_management_plugin.cc
@@ -0,0 +1,768 @@
+/*
+ Copyright (c) 2016 MariaDB Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+
+#include <my_global.h>
+#include <typelib.h>
+#include <mysql/plugin_encryption.h>
+#include <my_crypt.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <mysqld_error.h>
+#include <my_sys.h>
+#include <map>
+#include <algorithm>
+#include <string>
+#include <vector>
+#include <iterator>
+#include <sstream>
+#include <fstream>
+
+#ifndef _WIN32
+#include <dirent.h>
+#endif
+
+#include <aws/core/Aws.h>
+#include <aws/core/client/AWSError.h>
+#include <aws/core/utils/logging/AWSLogging.h>
+#include <aws/core/utils/logging/ConsoleLogSystem.h>
+#include <aws/kms/KMSClient.h>
+#include <aws/kms/model/DecryptRequest.h>
+#include <aws/kms/model/DecryptResult.h>
+#include <aws/kms/model/GenerateDataKeyWithoutPlaintextRequest.h>
+#include <aws/kms/model/GenerateDataKeyWithoutPlaintextResult.h>
+#include <aws/core/utils/Outcome.h>
+
+using namespace std;
+using namespace Aws::KMS;
+using namespace Aws::KMS::Model;
+using namespace Aws::Utils::Logging;
+
+
+/* Plaintext key info struct */
+struct KEY_INFO
+{
+ unsigned int key_id;
+ unsigned int key_version;
+ unsigned int length;
+ unsigned char data[MY_AES_MAX_KEY_LENGTH];
+ bool load_failed; /* if true, do not attempt to reload?*/
+public:
+ KEY_INFO() : key_id(0), key_version(0), length(0), load_failed(false){};
+};
+#define KEY_ID_AND_VERSION(key_id,version) ((longlong)key_id << 32 | version)
+
+/* Cache for the latest version, per key id */
+static std::map<uint, uint> latest_version_cache;
+
+/* Cache for plaintext keys */
+static std::map<ulonglong, KEY_INFO> key_info_cache;
+
+static const char *key_spec_names[]={ "AES_128", "AES_256", 0 };
+
+/* Plugin variables */
+static char* master_key_id;
+static char* region;
+static unsigned long key_spec;
+static unsigned long log_level;
+static int rotate_key;
+static int request_timeout;
+static char* endpoint_url;
+
+#ifndef DBUG_OFF
+#define WITH_AWS_MOCK 1
+#else
+#define WITH_AWS_MOCK 0
+#endif
+
+#if WITH_AWS_MOCK
+static char mock;
+#endif
+
+
+/* AWS functionality*/
+static int read_and_decrypt_key(const char *path, KEY_INFO *info);
+static int generate_and_save_datakey(uint key_id, uint version);
+
+static int extract_id_and_version(const char *name, uint *id, uint *ver);
+static unsigned int get_latest_key_version(unsigned int key_id);
+static unsigned int get_latest_key_version_nolock(unsigned int key_id);
+static int load_key(KEY_INFO *info);
+static std::mutex mtx;
+
+
+static Aws::KMS::KMSClient *client;
+
+static void print_kms_error(const char *func, const Aws::Client::AWSError<Aws::KMS::KMSErrors>& err)
+{
+ my_printf_error(ER_UNKNOWN_ERROR,
+ "AWS KMS plugin : KMS Client API '%s' failed : %s - %s",
+ ME_ERROR_LOG_ONLY,
+ func, err.GetExceptionName().c_str(), err.GetMessage().c_str());
+}
+
+#if WITH_AWS_MOCK
+/*
+ Mock routines to test plugin without actual AWS KMS interaction
+ we only need to mock 2 functions - generating encrypted key, and decrypt
+
+ This mock functions do no-op encryption, i.e encrypt and decrypt of
+ a buffer return the buffer itself.
+*/
+
+/*
+ Generate random "encrypted" key. We do not encrypt anything in mock mode.
+*/
+static int mock_generate_encrypted_key(Aws::Utils::ByteBuffer *result)
+{
+ size_t len = key_spec == 0?16 : 32;
+ *result = Aws::Utils::ByteBuffer(len);
+ my_random_bytes(result->GetUnderlyingData(), (int)len);
+ return 0;
+}
+
+
+static int mock_decrypt(Aws::Utils::ByteBuffer input, Aws::Utils::ByteBuffer* output)
+{
+ /* We do not encrypt or decrypt in mock mode.*/
+ *output = input;
+ return 0;
+}
+#endif
+
+/* Redirect AWS trace to error log */
+class MySQLLogSystem : public Aws::Utils::Logging::FormattedLogSystem
+{
+public:
+
+ using Base = FormattedLogSystem;
+ MySQLLogSystem(LogLevel logLevel) :
+ Base(logLevel)
+ {
+ }
+ virtual LogLevel GetLogLevel(void) const override
+ {
+ return (LogLevel)log_level;
+ }
+ virtual ~MySQLLogSystem()
+ {
+ }
+
+ virtual void Flush(void) override
+ {
+ }
+
+protected:
+ virtual void ProcessFormattedStatement(Aws::String&& statement) override
+ {
+#ifdef _WIN32
+ /*
+ On Windows, we can't use C runtime functions to write to stdout,
+ because we compile with static C runtime, so plugin has a stdout
+ different from server. Thus we're using WriteFile().
+ */
+ DWORD nSize= (DWORD)statement.size();
+ DWORD nWritten;
+ const char *s= statement.c_str();
+ HANDLE h= GetStdHandle(STD_OUTPUT_HANDLE);
+
+ WriteFile(h, s, nSize, &nWritten, NULL);
+#else
+ printf("%s", statement.c_str());
+#endif
+ }
+};
+
+/* Get list of files in current directory */
+static vector<string> traverse_current_directory()
+{
+ vector<string> v;
+#ifdef _WIN32
+ WIN32_FIND_DATA find_data;
+ HANDLE h= FindFirstFile("*.*", &find_data);
+ if (h == INVALID_HANDLE_VALUE)
+ return v;
+ do
+ {
+ v.push_back(find_data.cFileName);
+ }
+ while (FindNextFile(h, &find_data));
+ FindClose(h);
+#else
+ DIR *dir = opendir(".");
+ if (!dir)
+ return v;
+ struct dirent *e;
+ while ((e= readdir(dir)))
+ v.push_back(e->d_name);
+ closedir(dir);
+#endif
+ return v;
+}
+
+Aws::SDKOptions sdkOptions;
+
+static int aws_init()
+{
+
+#ifdef HAVE_WOLFSSL
+ sdkOptions.cryptoOptions.initAndCleanupOpenSSL = true;
+#else
+ /* Server initialized OpenSSL already, thus AWS must skip it */
+ sdkOptions.cryptoOptions.initAndCleanupOpenSSL = false;
+#endif
+
+ Aws::InitAPI(sdkOptions);
+ InitializeAWSLogging(Aws::MakeShared<MySQLLogSystem>("aws_key_management_plugin", (Aws::Utils::Logging::LogLevel) log_level));
+
+ Aws::Client::ClientConfiguration clientConfiguration;
+ if (region && region[0])
+ {
+ clientConfiguration.region = region;
+ }
+ if (endpoint_url && endpoint_url[0])
+ {
+ clientConfiguration.endpointOverride = endpoint_url;
+ }
+ if (request_timeout)
+ {
+ clientConfiguration.requestTimeoutMs= request_timeout;
+ clientConfiguration.connectTimeoutMs= request_timeout;
+ }
+ client = new KMSClient(clientConfiguration);
+ if (!client)
+ {
+ my_printf_error(ER_UNKNOWN_ERROR, "Can't initialize KMS client", ME_ERROR_LOG_ONLY | ME_WARNING);
+ return -1;
+ }
+ return 0;
+}
+
+static int init()
+{
+#if WITH_AWS_MOCK
+ if(mock)
+ return 0;
+#endif
+ return aws_init();
+}
+
+/*
+ Plugin initialization.
+
+ Create KMS client and scan datadir to find out which keys and versions
+ are present.
+*/
+static int plugin_init(void *p)
+{
+ if (init())
+ return -1;
+
+ vector<string> files= traverse_current_directory();
+ for (size_t i=0; i < files.size(); i++)
+ {
+
+ KEY_INFO info;
+ if (extract_id_and_version(files[i].c_str(), &info.key_id, &info.key_version) == 0)
+ {
+ key_info_cache[KEY_ID_AND_VERSION(info.key_id, info.key_version)]= info;
+ latest_version_cache[info.key_id]= max(info.key_version, latest_version_cache[info.key_id]);
+ }
+ }
+ return 0;
+}
+
+
+static void aws_shutdown()
+{
+ delete client;
+ ShutdownAWSLogging();
+ Aws::ShutdownAPI(sdkOptions);
+}
+
+
+static void shutdown()
+{
+#if WITH_AWS_MOCK
+ if(mock)
+ return;
+#endif
+ aws_shutdown();
+}
+
+
+static int plugin_deinit(void *p)
+{
+ latest_version_cache.clear();
+ key_info_cache.clear();
+ shutdown();
+ return 0;
+}
+
+/* Generate filename to store the ciphered key */
+static void format_keyfile_name(char *buf, size_t size, uint key_id, uint version)
+{
+ snprintf(buf, size, "aws-kms-key.%u.%u", key_id, version);
+}
+
+/* Extract key id and version from file name */
+static int extract_id_and_version(const char *name, uint *id, uint *ver)
+{
+ int len;
+ int n= sscanf(name, "aws-kms-key.%u.%u%n", id, ver, &len);
+ if (n == 2 && *id > 0 && *ver > 0 && len == (int)strlen(name))
+ return 0;
+ return 1;
+}
+
+/*
+ Decrypt key stored in aws-kms-key.<id>.<version>
+ Cache the decrypted key.
+*/
+static int load_key(KEY_INFO *info)
+{
+ int ret;
+ char path[256];
+
+ format_keyfile_name(path, sizeof(path), info->key_id, info->key_version);
+ ret= read_and_decrypt_key(path, info);
+ if (ret)
+ info->load_failed= true;
+
+ latest_version_cache[info->key_id]= max(latest_version_cache[info->key_id], info->key_version);
+ key_info_cache[KEY_ID_AND_VERSION(info->key_id, info->key_version)]= *info;
+
+ if (!ret)
+ {
+ my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: loaded key %u, version %u, key length %u bit", ME_ERROR_LOG_ONLY | ME_NOTE,
+ info->key_id, info->key_version,(uint)info->length*8);
+ }
+ else
+ {
+ my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: key %u, version %u could not be decrypted", ME_ERROR_LOG_ONLY | ME_WARNING,
+ info->key_id, info->key_version);
+ }
+ return ret;
+}
+
+
+/*
+ Get latest version for the key.
+
+ If key is not decrypted yet, this function also decrypt the key
+ and error will be returned if decryption fails.
+
+ The reason for that is that Innodb crashes
+ in case errors are returned by get_key(),
+
+ A new key will be created if it does not exist, provided there is
+ valid master_key_id.
+*/
+static unsigned int get_latest_key_version(unsigned int key_id)
+{
+ unsigned int ret;
+ mtx.lock();
+ ret= get_latest_key_version_nolock(key_id);
+ mtx.unlock();
+ return ret;
+}
+
+static unsigned int get_latest_key_version_nolock(unsigned int key_id)
+{
+ KEY_INFO info;
+ uint ver;
+
+ ver= latest_version_cache[key_id];
+ if (ver > 0)
+ {
+ info= key_info_cache[KEY_ID_AND_VERSION(key_id, ver)];
+ }
+ if (info.load_failed)
+ {
+ /* Decryption failed previously, don't retry */
+ return(ENCRYPTION_KEY_VERSION_INVALID);
+ }
+ else if (ver > 0)
+ {
+ /* Key exists already, return it*/
+ if (info.length > 0)
+ return(ver);
+ }
+ else // (ver == 0)
+ {
+ /* Generate a new key, version 1 */
+ if (generate_and_save_datakey(key_id, 1) != 0)
+ return(ENCRYPTION_KEY_VERSION_INVALID);
+ info.key_id= key_id;
+ info.key_version= 1;
+ info.length= 0;
+ }
+
+ if (load_key(&info))
+ return(ENCRYPTION_KEY_VERSION_INVALID);
+ return(info.key_version);
+}
+
+/* Decrypt Byte buffer with AWS. */
+static int aws_decrypt(Aws::Utils::ByteBuffer input, Aws::Utils::ByteBuffer* output)
+{
+ DecryptRequest request;
+ request.SetCiphertextBlob(input);
+ DecryptOutcome outcome = client->Decrypt(request);
+ if (!outcome.IsSuccess())
+ {
+ print_kms_error("Decrypt", outcome.GetError());
+ return -1;
+ }
+ *output= outcome.GetResult().GetPlaintext();
+ return 0;
+}
+
+
+static int decrypt(Aws::Utils::ByteBuffer input, Aws::Utils::ByteBuffer* output)
+{
+#if WITH_AWS_MOCK
+ if(mock)
+ return mock_decrypt(input,output);
+#endif
+ return aws_decrypt(input, output);
+}
+
+/*
+ Decrypt a file with KMS
+*/
+static int read_and_decrypt_key(const char *path, KEY_INFO *info)
+{
+
+ /* Read file content into memory */
+ ifstream ifs(path, ios::binary | ios::ate);
+ if (!ifs.good())
+ {
+ my_printf_error(ER_UNKNOWN_ERROR, "can't open file %s", ME_ERROR_LOG_ONLY, path);
+ return(-1);
+ }
+ size_t pos = (size_t)ifs.tellg();
+ if (!pos || pos == SIZE_T_MAX)
+ {
+ my_printf_error(ER_UNKNOWN_ERROR, "invalid key file %s", ME_ERROR_LOG_ONLY, path);
+ return(-1);
+ }
+ std::vector<char> contents(pos);
+ ifs.seekg(0, ios::beg);
+ ifs.read(&contents[0], pos);
+
+ /* Decrypt data the with AWS */
+
+ Aws::Utils::ByteBuffer input((unsigned char *)contents.data(), pos);
+ Aws::Utils::ByteBuffer plaintext;
+
+ if (decrypt(input, &plaintext))
+ {
+ return -1;
+ }
+
+ size_t len = plaintext.GetLength();
+
+ if (len > sizeof(info->data))
+ {
+ my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: encoding key too large for %s", ME_ERROR_LOG_ONLY, path);
+ return(ENCRYPTION_KEY_BUFFER_TOO_SMALL);
+ }
+ memcpy(info->data, plaintext.GetUnderlyingData(), len);
+ info->length= (unsigned int)len;
+ return(0);
+}
+
+
+int aws_generate_encrypted_key(Aws::Utils::ByteBuffer *result)
+{
+ if (!master_key_id[0])
+ {
+ my_printf_error(ER_UNKNOWN_ERROR,
+ "Can't generate encryption key, because 'aws_key_management_master_key_id' parameter is not set",
+ MYF(0));
+ return(-1);
+ }
+ GenerateDataKeyWithoutPlaintextRequest request;
+ request.SetKeyId(master_key_id);
+ request.SetKeySpec(DataKeySpecMapper::GetDataKeySpecForName(key_spec_names[key_spec]));
+
+ GenerateDataKeyWithoutPlaintextOutcome outcome;
+ outcome= client->GenerateDataKeyWithoutPlaintext(request);
+ if (!outcome.IsSuccess())
+ {
+ print_kms_error("GenerateDataKeyWithoutPlaintext", outcome.GetError());
+ return(-1);
+ }
+ *result = outcome.GetResult().GetCiphertextBlob();
+ return 0;
+}
+
+
+static int generate_encrypted_key(Aws::Utils::ByteBuffer *output)
+{
+#if WITH_AWS_MOCK
+ if(mock)
+ return mock_generate_encrypted_key(output);
+#endif
+ return aws_generate_encrypted_key(output);
+}
+
+/* Generate a new datakey and store it a file */
+static int generate_and_save_datakey(uint keyid, uint version)
+{
+ Aws::Utils::ByteBuffer byteBuffer;
+
+ if (generate_encrypted_key(&byteBuffer))
+ return -1;
+
+ string out;
+ char filename[20];
+ format_keyfile_name(filename, sizeof(filename), keyid, version);
+ int fd= open(filename, O_WRONLY |O_CREAT|O_BINARY, IF_WIN(_S_IREAD, S_IRUSR| S_IRGRP| S_IROTH));
+ if (fd < 0)
+ {
+ my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: Can't create file %s", ME_ERROR_LOG_ONLY, filename);
+ return(-1);
+ }
+ unsigned int len= (unsigned int)byteBuffer.GetLength();
+ if (write(fd, byteBuffer.GetUnderlyingData(), len) != len)
+ {
+ my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: can't write to %s", ME_ERROR_LOG_ONLY, filename);
+ close(fd);
+ unlink(filename);
+ return(-1);
+ }
+ close(fd);
+ my_printf_error(ER_UNKNOWN_ERROR, "AWS KMS plugin: generated encrypted datakey for key id=%u, version=%u", ME_ERROR_LOG_ONLY | ME_NOTE,
+ keyid, version);
+ return(0);
+}
+
+/* Key rotation for a single key */
+static int rotate_single_key(uint key_id)
+{
+ uint ver;
+ ver= latest_version_cache[key_id];
+
+ if (!ver)
+ {
+ my_printf_error(ER_UNKNOWN_ERROR, "key %u does not exist", MYF(ME_WARNING), key_id);
+ return -1;
+ }
+ else if (generate_and_save_datakey(key_id, ver + 1))
+ {
+ my_printf_error(ER_UNKNOWN_ERROR, "Could not generate datakey for key id= %u, ver= %u",
+ MYF(ME_WARNING), key_id, ver);
+ return -1;
+ }
+ else
+ {
+ KEY_INFO info;
+ info.key_id= key_id;
+ info.key_version = ver + 1;
+ if (load_key(&info))
+ {
+ my_printf_error(ER_UNKNOWN_ERROR, "Could not load datakey for key id= %u, ver= %u",
+ MYF(ME_WARNING), key_id, ver);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/* Key rotation for all key ids */
+static int rotate_all_keys()
+{
+ int ret= 0;
+ for (map<uint, uint>::iterator it= latest_version_cache.begin(); it != latest_version_cache.end(); it++)
+ {
+ ret= rotate_single_key(it->first);
+ if (ret)
+ break;
+ }
+ return ret;
+}
+
+static void update_rotate(MYSQL_THD, struct st_mysql_sys_var *, void *, const void *val)
+{
+ if (!master_key_id[0])
+ {
+ my_printf_error(ER_UNKNOWN_ERROR,
+ "aws_key_management_master_key_id must be set to generate new data keys", MYF(ME_WARNING));
+ return;
+ }
+ mtx.lock();
+ rotate_key= *(int *)val;
+ switch (rotate_key)
+ {
+ case 0:
+ break;
+ case -1:
+ rotate_all_keys();
+ break;
+ default:
+ rotate_single_key(rotate_key);
+ break;
+ }
+ rotate_key= 0;
+ mtx.unlock();
+}
+
+static unsigned int get_key(
+ unsigned int key_id,
+ unsigned int version,
+ unsigned char* dstbuf,
+ unsigned int* buflen)
+{
+ KEY_INFO info;
+
+ mtx.lock();
+ info= key_info_cache[KEY_ID_AND_VERSION(key_id, version)];
+ if (info.length == 0 && !info.load_failed)
+ {
+ info.key_id= key_id;
+ info.key_version= version;
+ load_key(&info);
+ }
+ mtx.unlock();
+ if (info.load_failed)
+ return(ENCRYPTION_KEY_VERSION_INVALID);
+ if (*buflen < info.length)
+ {
+ *buflen= info.length;
+ return(ENCRYPTION_KEY_BUFFER_TOO_SMALL);
+ }
+ *buflen= info.length;
+ memcpy(dstbuf, info.data, info.length);
+ return(0);
+}
+
+
+/* Plugin defs */
+struct st_mariadb_encryption aws_key_management_plugin= {
+ MariaDB_ENCRYPTION_INTERFACE_VERSION,
+ get_latest_key_version,
+ get_key,
+ // use default encrypt/decrypt functions
+ 0, 0, 0, 0, 0
+};
+
+
+static TYPELIB key_spec_typelib =
+{
+ array_elements(key_spec_names) - 1, "",
+ key_spec_names, NULL
+};
+
+const char *log_level_names[] =
+{
+ "Off",
+ "Fatal",
+ "Error",
+ "Warn",
+ "Info",
+ "Debug",
+ "Trace",
+ 0
+};
+
+static TYPELIB log_level_typelib =
+{
+ array_elements(log_level_names) - 1, "",
+ log_level_names, NULL
+};
+
+static MYSQL_SYSVAR_STR(master_key_id, master_key_id,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
+ "Key id for master encryption key. Used to create new datakeys. If not set, no new keys will be created",
+ NULL, NULL, "");
+
+static MYSQL_SYSVAR_ENUM(key_spec, key_spec,
+ PLUGIN_VAR_RQCMDARG,
+ "Encryption algorithm used to create new keys.",
+ NULL, NULL, 0, &key_spec_typelib);
+
+
+static MYSQL_SYSVAR_ENUM(log_level, log_level,
+ PLUGIN_VAR_RQCMDARG,
+ "Logging for AWS API",
+ NULL, NULL, 0, &log_level_typelib);
+
+
+static MYSQL_SYSVAR_INT(rotate_key, rotate_key,
+ PLUGIN_VAR_RQCMDARG,
+ "Set this variable to key id to perform rotation of the key. Specify -1 to rotate all keys",
+ NULL, update_rotate, 0, -1, INT_MAX, 1);
+
+
+static MYSQL_SYSVAR_INT(request_timeout, request_timeout,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "Timeout in milliseconds for create HTTPS connection or execute AWS request. Specify 0 to use SDK default.",
+ NULL, NULL, 0, 0, INT_MAX, 1);
+
+static MYSQL_SYSVAR_STR(region, region,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "AWS region. For example us-east-1, or eu-central-1. If no value provided, SDK default is used.",
+ NULL, NULL, "");
+
+static MYSQL_SYSVAR_STR(endpoint_url, endpoint_url,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "Used to override the default AWS API endpoint. If not set, the default will be used",
+ NULL, NULL, "");
+
+#if WITH_AWS_MOCK
+static MYSQL_SYSVAR_BOOL(mock, mock,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "Mock AWS KMS calls (for testing).",
+ NULL, NULL, 0);
+#endif
+
+static struct st_mysql_sys_var* settings[]= {
+ MYSQL_SYSVAR(master_key_id),
+ MYSQL_SYSVAR(key_spec),
+ MYSQL_SYSVAR(rotate_key),
+ MYSQL_SYSVAR(log_level),
+ MYSQL_SYSVAR(request_timeout),
+ MYSQL_SYSVAR(region),
+ MYSQL_SYSVAR(endpoint_url),
+#if WITH_AWS_MOCK
+ MYSQL_SYSVAR(mock),
+#endif
+ NULL
+};
+
+/*
+ Plugin library descriptor
+*/
+maria_declare_plugin(aws_key_management)
+{
+ MariaDB_ENCRYPTION_PLUGIN,
+ &aws_key_management_plugin,
+ "aws_key_management",
+ "MariaDB Corporation",
+ "AWS key management plugin",
+ PLUGIN_LICENSE_GPL,
+ plugin_init,
+ plugin_deinit,
+ 0x0100,
+ NULL,
+ settings,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
diff --git a/plugin/cracklib_password_check/CMakeLists.txt b/plugin/cracklib_password_check/CMakeLists.txt
new file mode 100644
index 00000000..81db865e
--- /dev/null
+++ b/plugin/cracklib_password_check/CMakeLists.txt
@@ -0,0 +1,13 @@
+INCLUDE (CheckIncludeFiles)
+INCLUDE (CheckLibraryExists)
+
+CHECK_LIBRARY_EXISTS(crack FascistCheckUser "" HAVE_LIBCRACK)
+
+SET(CMAKE_REQUIRED_DEFINITIONS -Dsize_t=int) # debian hack, debian bug.
+CHECK_INCLUDE_FILES (crack.h HAVE_CRACK_H)
+
+IF (HAVE_ALLOCA_H AND HAVE_CRACK_H AND HAVE_LIBCRACK AND HAVE_MEMCPY)
+ MYSQL_ADD_PLUGIN(cracklib_password_check cracklib_password_check.c
+ LINK_LIBRARIES crack MODULE_ONLY
+ COMPONENT cracklib-password-check)
+ENDIF()
diff --git a/plugin/cracklib_password_check/cracklib_password_check.c b/plugin/cracklib_password_check/cracklib_password_check.c
new file mode 100644
index 00000000..20294b07
--- /dev/null
+++ b/plugin/cracklib_password_check/cracklib_password_check.c
@@ -0,0 +1,83 @@
+/* Copyright (c) 2014, Sergei Golubchik and MariaDB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include <mysql/plugin_password_validation.h>
+#include <crack.h>
+#include <string.h>
+#include <alloca.h>
+#include <mysqld_error.h>
+
+static char *dictionary;
+
+static int crackme(const MYSQL_CONST_LEX_STRING *username,
+ const MYSQL_CONST_LEX_STRING *password)
+{
+ char *user= alloca(username->length + 1);
+ char *host;
+ const char *res;
+
+ memcpy(user, username->str, username->length);
+ user[username->length]= 0;
+ if ((host= strchr(user, '@')))
+ *host++= 0;
+
+ if ((res= FascistCheckUser(password->str, dictionary, user, host)))
+ {
+ my_printf_error(ER_NOT_VALID_PASSWORD, "cracklib: %s",
+ ME_WARNING, res);
+ return 1;
+ }
+
+ return 0;
+}
+
+static MYSQL_SYSVAR_STR(dictionary, dictionary, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "Path to a cracklib dictionary", NULL, NULL, 0);
+
+/* optional user-friendly nicety */
+void set_default_dictionary_path() __attribute__((constructor));
+void set_default_dictionary_path()
+{
+ MYSQL_SYSVAR_NAME(dictionary).def_val = GetDefaultCracklibDict();
+}
+
+static struct st_mysql_sys_var* sysvars[]= {
+ MYSQL_SYSVAR(dictionary),
+ NULL
+};
+
+static struct st_mariadb_password_validation info=
+{
+ MariaDB_PASSWORD_VALIDATION_INTERFACE_VERSION,
+ crackme
+};
+
+maria_declare_plugin(cracklib_password_check)
+{
+ MariaDB_PASSWORD_VALIDATION_PLUGIN,
+ &info,
+ "cracklib_password_check",
+ "Sergei Golubchik",
+ "Password validation via CrackLib",
+ PLUGIN_LICENSE_GPL,
+ NULL,
+ NULL,
+ 0x0100,
+ NULL,
+ sysvars,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
diff --git a/plugin/daemon_example/AUTHORS b/plugin/daemon_example/AUTHORS
new file mode 100644
index 00000000..fe992df1
--- /dev/null
+++ b/plugin/daemon_example/AUTHORS
@@ -0,0 +1 @@
+Brian Aker <brian@mysql.com>
diff --git a/plugin/daemon_example/CMakeLists.txt b/plugin/daemon_example/CMakeLists.txt
new file mode 100644
index 00000000..57a1135e
--- /dev/null
+++ b/plugin/daemon_example/CMakeLists.txt
@@ -0,0 +1,20 @@
+# Copyright (c) 2006, 2011, 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
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
+
+MYSQL_ADD_PLUGIN(daemon_example daemon_example.cc RECOMPILE_FOR_EMBEDDED
+ MODULE_ONLY MODULE_OUTPUT_NAME "libdaemon_example" COMPONENT Test)
+
+INSTALL(FILES daemon_example.ini DESTINATION ${INSTALL_PLUGINDIR}
+ COMPONENT Test)
diff --git a/plugin/daemon_example/ChangeLog b/plugin/daemon_example/ChangeLog
new file mode 100644
index 00000000..c4b09806
--- /dev/null
+++ b/plugin/daemon_example/ChangeLog
@@ -0,0 +1,2 @@
+0.1
+ - Added
diff --git a/plugin/daemon_example/NEWS b/plugin/daemon_example/NEWS
new file mode 100644
index 00000000..ddae9fc3
--- /dev/null
+++ b/plugin/daemon_example/NEWS
@@ -0,0 +1,2 @@
+0.1 - Tue Nov 7 12:08:03 PST 2006
+ * Added Example to test interface
diff --git a/plugin/daemon_example/README b/plugin/daemon_example/README
new file mode 100644
index 00000000..d3c67be6
--- /dev/null
+++ b/plugin/daemon_example/README
@@ -0,0 +1,8 @@
+Hi!
+
+This is an example of a daemon plugin. These are generic plugins that
+only hook ino the startup and shutdown of the database.
+
+Cheers,
+ -Brian
+ Seattle, WA
diff --git a/plugin/daemon_example/daemon_example.cc b/plugin/daemon_example/daemon_example.cc
new file mode 100644
index 00000000..50026e92
--- /dev/null
+++ b/plugin/daemon_example/daemon_example.cc
@@ -0,0 +1,214 @@
+/* Copyright (c) 2006, 2015, 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
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include <my_global.h>
+#include <sql_priv.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <mysql_version.h>
+#include <mysql/plugin.h>
+#include <my_dir.h>
+#include "my_pthread.h" // pthread_handler_t
+#include "my_sys.h" // my_write, my_malloc
+#include "m_string.h" // strlen
+#include "sql_plugin.h" // st_plugin_int
+
+/*
+ Disable __attribute__() on non-gcc compilers.
+*/
+#if !defined(__attribute__) && !defined(__GNUC__)
+#define __attribute__(A)
+#endif
+
+
+#define HEART_STRING_BUFFER 100
+
+struct mysql_heartbeat_context
+{
+ pthread_t heartbeat_thread;
+ File heartbeat_file;
+};
+
+pthread_handler_t mysql_heartbeat(void *p)
+{
+ DBUG_ENTER("mysql_heartbeat");
+ struct mysql_heartbeat_context *con= (struct mysql_heartbeat_context *)p;
+ char buffer[HEART_STRING_BUFFER];
+ time_t result;
+ struct tm tm_tmp;
+
+ while(1)
+ {
+ sleep(5);
+
+ result= time(NULL);
+ localtime_r(&result, &tm_tmp);
+ my_snprintf(buffer, sizeof(buffer),
+ "Heartbeat at %02d%02d%02d %2d:%02d:%02d\n",
+ tm_tmp.tm_year % 100,
+ tm_tmp.tm_mon+1,
+ tm_tmp.tm_mday,
+ tm_tmp.tm_hour,
+ tm_tmp.tm_min,
+ tm_tmp.tm_sec);
+ my_write(con->heartbeat_file, (uchar*) buffer, strlen(buffer), MYF(0));
+ }
+
+ DBUG_RETURN(0);
+}
+
+/*
+ Initialize the daemon example at server start or plugin installation.
+
+ SYNOPSIS
+ daemon_example_plugin_init()
+
+ DESCRIPTION
+ Starts up heartbeatbeat thread
+
+ RETURN VALUE
+ 0 success
+ 1 failure (cannot happen)
+*/
+
+static int daemon_example_plugin_init(void *p __attribute__ ((unused)))
+{
+
+ DBUG_ENTER("daemon_example_plugin_init");
+ struct mysql_heartbeat_context *con;
+ pthread_attr_t attr; /* Thread attributes */
+ char heartbeat_filename[FN_REFLEN];
+ char buffer[HEART_STRING_BUFFER];
+ time_t result= time(NULL);
+ struct tm tm_tmp;
+
+ struct st_plugin_int *plugin= (struct st_plugin_int *)p;
+
+ con= (struct mysql_heartbeat_context *)
+ my_malloc(PSI_NOT_INSTRUMENTED, sizeof(struct mysql_heartbeat_context), MYF(0));
+
+ fn_format(heartbeat_filename, "mysql-heartbeat", "", ".log",
+ MY_REPLACE_EXT | MY_UNPACK_FILENAME);
+ unlink(heartbeat_filename);
+ con->heartbeat_file= my_open(heartbeat_filename, O_CREAT|O_RDWR, MYF(0));
+
+ /*
+ No threads exist at this point in time, so this is thread safe.
+ */
+ localtime_r(&result, &tm_tmp);
+ my_snprintf(buffer, sizeof(buffer),
+ "Starting up at %02d%02d%02d %2d:%02d:%02d\n",
+ tm_tmp.tm_year % 100,
+ tm_tmp.tm_mon+1,
+ tm_tmp.tm_mday,
+ tm_tmp.tm_hour,
+ tm_tmp.tm_min,
+ tm_tmp.tm_sec);
+ my_write(con->heartbeat_file, (uchar*) buffer, strlen(buffer), MYF(0));
+
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr,
+ PTHREAD_CREATE_JOINABLE);
+
+
+ /* now create the thread */
+ if (pthread_create(&con->heartbeat_thread, &attr, mysql_heartbeat,
+ (void *)con) != 0)
+ {
+ fprintf(stderr,"Could not create heartbeat thread!\n");
+ DBUG_RETURN(1);
+ }
+ plugin->data= (void *)con;
+
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Terminate the daemon example at server shutdown or plugin deinstallation.
+
+ SYNOPSIS
+ daemon_example_plugin_deinit()
+ Does nothing.
+
+ RETURN VALUE
+ 0 success
+ 1 failure (cannot happen)
+
+*/
+
+static int daemon_example_plugin_deinit(void *p __attribute__ ((unused)))
+{
+ DBUG_ENTER("daemon_example_plugin_deinit");
+ char buffer[HEART_STRING_BUFFER];
+ struct st_plugin_int *plugin= (struct st_plugin_int *)p;
+ struct mysql_heartbeat_context *con=
+ (struct mysql_heartbeat_context *)plugin->data;
+ time_t result= time(NULL);
+ struct tm tm_tmp;
+
+ pthread_cancel(con->heartbeat_thread);
+ pthread_join(con->heartbeat_thread, NULL);
+
+ localtime_r(&result, &tm_tmp);
+ my_snprintf(buffer, sizeof(buffer),
+ "Shutting down at %02d%02d%02d %2d:%02d:%02d\n",
+ tm_tmp.tm_year % 100,
+ tm_tmp.tm_mon+1,
+ tm_tmp.tm_mday,
+ tm_tmp.tm_hour,
+ tm_tmp.tm_min,
+ tm_tmp.tm_sec);
+ my_write(con->heartbeat_file, (uchar*) buffer, strlen(buffer), MYF(0));
+
+ /*
+ Need to wait for the hearbeat thread to terminate before closing
+ the file it writes to and freeing the memory it uses.
+ */
+ pthread_join(con->heartbeat_thread, NULL);
+
+ my_close(con->heartbeat_file, MYF(0));
+
+ my_free(con);
+
+ DBUG_RETURN(0);
+}
+
+
+struct st_mysql_daemon daemon_example_plugin=
+{ MYSQL_DAEMON_INTERFACE_VERSION };
+
+/*
+ Plugin library descriptor
+*/
+
+maria_declare_plugin(daemon_example)
+{
+ MYSQL_DAEMON_PLUGIN,
+ &daemon_example_plugin,
+ "daemon_example",
+ "Brian Aker",
+ "Daemon example, creates a heartbeat beat file in mysql-heartbeat.log",
+ PLUGIN_LICENSE_GPL,
+ daemon_example_plugin_init, /* Plugin Init */
+ daemon_example_plugin_deinit, /* Plugin Deinit */
+ 0x0100 /* 1.0 */,
+ NULL, /* status variables */
+ NULL, /* system variables */
+ "1.0", /* string version */
+ MariaDB_PLUGIN_MATURITY_EXPERIMENTAL /* maturity */
+}
+maria_declare_plugin_end;
diff --git a/plugin/daemon_example/daemon_example.ini b/plugin/daemon_example/daemon_example.ini
new file mode 100644
index 00000000..7c6d4d14
--- /dev/null
+++ b/plugin/daemon_example/daemon_example.ini
@@ -0,0 +1,9 @@
+#
+# Plugin configuration file. Place the following on a separate line:
+#
+# library binary file name (without .so or .dll)
+# component_name
+# [component_name] - additional components in plugin
+#
+libdaemon_example
+daemon_example
diff --git a/plugin/debug_key_management/CMakeLists.txt b/plugin/debug_key_management/CMakeLists.txt
new file mode 100644
index 00000000..eeb8a3bf
--- /dev/null
+++ b/plugin/debug_key_management/CMakeLists.txt
@@ -0,0 +1,2 @@
+MYSQL_ADD_PLUGIN(DEBUG_KEY_MANAGEMENT debug_key_management_plugin.cc
+ MODULE_ONLY COMPONENT Test)
diff --git a/plugin/debug_key_management/debug_key_management_plugin.cc b/plugin/debug_key_management/debug_key_management_plugin.cc
new file mode 100644
index 00000000..74ab3522
--- /dev/null
+++ b/plugin/debug_key_management/debug_key_management_plugin.cc
@@ -0,0 +1,100 @@
+/*
+ Copyright (c) 2015 MariaDB Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/**
+ Debug key management plugin.
+ It's used to debug the encryption code with a fixed keys that change
+ only on user request.
+
+ It does not support different key ids, the only valid key id is 1.
+
+ THIS IS AN EXAMPLE ONLY! ENCRYPTION KEYS ARE HARD-CODED AND *NOT* SECRET!
+ DO NOT USE THIS PLUGIN IN PRODUCTION! EVER!
+*/
+
+#include <my_global.h>
+#include <mysql/plugin_encryption.h>
+#include <string.h>
+#include <myisampack.h>
+
+#define KEY_SIZE 16
+
+static uint key_version;
+
+static MYSQL_SYSVAR_UINT(version, key_version, PLUGIN_VAR_RQCMDARG,
+ "Latest key version", NULL, NULL, 1, 0, UINT_MAX, 1);
+
+static struct st_mysql_sys_var* sysvars[] = {
+ MYSQL_SYSVAR(version),
+ NULL
+};
+
+static unsigned int get_latest_key_version(unsigned int keyid)
+{
+ if (keyid != 1)
+ return ENCRYPTION_KEY_VERSION_INVALID;
+
+ return key_version;
+}
+
+static unsigned int get_key(unsigned int keyid, unsigned int version,
+ unsigned char* dstbuf, unsigned *buflen)
+{
+ if (keyid != 1)
+ return ENCRYPTION_KEY_VERSION_INVALID;
+
+ if (*buflen < KEY_SIZE)
+ {
+ *buflen= KEY_SIZE;
+ return ENCRYPTION_KEY_BUFFER_TOO_SMALL;
+ }
+ *buflen= KEY_SIZE;
+ if (!dstbuf)
+ return 0;
+
+ memset(dstbuf, 0, KEY_SIZE);
+ mi_int4store(dstbuf, version);
+ return 0;
+}
+
+struct st_mariadb_encryption debug_key_management_plugin= {
+ MariaDB_ENCRYPTION_INTERFACE_VERSION,
+ get_latest_key_version,
+ get_key,
+ // use default encrypt/decrypt functions
+ 0, 0, 0, 0, 0
+};
+
+/*
+ Plugin library descriptor
+*/
+maria_declare_plugin(debug_key_management)
+{
+ MariaDB_ENCRYPTION_PLUGIN,
+ &debug_key_management_plugin,
+ "debug_key_management",
+ "Sergei Golubchik",
+ "Debug key management plugin",
+ PLUGIN_LICENSE_GPL,
+ NULL,
+ NULL,
+ 0x0100,
+ NULL,
+ sysvars,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_EXPERIMENTAL
+}
+maria_declare_plugin_end;
diff --git a/plugin/disks/CMakeLists.txt b/plugin/disks/CMakeLists.txt
new file mode 100644
index 00000000..446c64d0
--- /dev/null
+++ b/plugin/disks/CMakeLists.txt
@@ -0,0 +1,5 @@
+IF("${CMAKE_SYSTEM}" MATCHES "Linux")
+ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql)
+ MYSQL_ADD_PLUGIN(DISKS information_schema_disks.cc MODULE_ONLY RECOMPILE_FOR_EMBEDDED)
+ENDIF()
+
diff --git a/plugin/disks/README.txt b/plugin/disks/README.txt
new file mode 100644
index 00000000..b49db3c0
--- /dev/null
+++ b/plugin/disks/README.txt
@@ -0,0 +1,86 @@
+Information Schema Disks
+------------------------
+This is a proof-of-concept information schema plugin that allows the
+disk space situation to be monitored. When installed, it can be used
+as follows:
+
+ > select * from information_schema.disks;
+ +-----------+-----------------------+-----------+----------+-----------+
+ | Disk | Path | Total | Used | Available |
+ +-----------+-----------------------+-----------+----------+-----------+
+ | /dev/sda3 | / | 47929956 | 30666304 | 14805864 |
+ | /dev/sda1 | /boot/efi | 191551 | 3461 | 188090 |
+ | /dev/sda4 | /home | 174679768 | 80335392 | 85448120 |
+ | /dev/sdb1 | /mnt/hdd | 961301832 | 83764 | 912363644 |
+ | /dev/sdb1 | /home/wikman/Music | 961301832 | 83764 | 912363644 |
+ | /dev/sdb1 | /home/wikman/Videos | 961301832 | 83764 | 912363644 |
+ | /dev/sdb1 | /home/wikman/hdd | 961301832 | 83764 | 912363644 |
+ | /dev/sdb1 | /home/wikman/Pictures | 961301832 | 83764 | 912363644 |
+ | /dev/sda3 | /var/lib/docker/aufs | 47929956 | 30666304 | 14805864 |
+ +-----------+-----------------------+-----------+----------+-----------+
+ 9 rows in set (0.00 sec)
+
+- 'Disk' is the name of the disk itself.
+- 'Path' is the mount point of the disk.
+- 'Total' is the total space in KiB.
+- 'Used' is the used amount of space in KiB, and
+- 'Available' is the amount of space in KiB available to non-root users.
+
+Note that as the amount of space available to root may be more that what
+is available to non-root users, 'available' + 'used' may be less than 'total'.
+
+All paths to which a particular disk has been mounted are reported. The
+rationale is that someone might want to take different action e.g. depending
+on which disk is relevant for a particular path. This leads to the same disk
+being reported multiple times. An alternative to this would be to have two
+tables; disks and mounts.
+
+ > select * from information_schema.disks;
+ +-----------+-----------+----------+-----------+
+ | Disk | Total | Used | Available |
+ +-----------+-----------+----------+-----------+
+ | /dev/sda3 | 47929956 | 30666304 | 14805864 |
+ | /dev/sda1 | 191551 | 3461 | 188090 |
+ | /dev/sda4 | 174679768 | 80335392 | 85448120 |
+ | /dev/sdb1 | 961301832 | 83764 | 912363644 |
+ +-----------+-----------+----------+-----------+
+
+ > select * from information_schema.mounts;
+ +-----------------------+-----------+
+ | Path | Disk |
+ +-----------------------+-----------+
+ | / | /dev/sda3 |
+ | /boot/efi | /dev/sda1 |
+ | /home | /dev/sda4 |
+ | /mnt/hdd | /dev/sdb1 |
+ | /home/wikman/Music | /dev/sdb1 |
+ ...
+
+
+Installation
+------------
+
+- Use "install plugin" or "install soname" command:
+
+ MariaDB [(none)]> install plugin disks soname 'disks.so';
+
+ or
+
+ MariaDB [(none)]> install soname 'disks.so';
+
+Usage
+-----
+The plugin appears as the table 'disks' in 'information_schema'.
+
+ MariaDB [(none)]> select * from information_schema.disks;
+ +-----------+-----------------------+-----------+----------+-----------+
+ | Disk | Path | Total | Used | Available |
+ +-----------+-----------------------+-----------+----------+-----------+
+ | /dev/sda3 | / | 47929956 | 30666308 | 14805860 |
+ | /dev/sda1 | /boot/efi | 191551 | 3461 | 188090 |
+ | /dev/sda4 | /home | 174679768 | 80348148 | 85435364 |
+ | /dev/sdb1 | /mnt/hdd | 961301832 | 83764 | 912363644 |
+ | /dev/sdb1 | /home/wikman/Music | 961301832 | 83764 | 912363644 |
+ | /dev/sdb1 | /home/wikman/Videos | 961301832 | 83764 | 912363644 |
+ ...
+
diff --git a/plugin/disks/information_schema_disks.cc b/plugin/disks/information_schema_disks.cc
new file mode 100644
index 00000000..042cfaff
--- /dev/null
+++ b/plugin/disks/information_schema_disks.cc
@@ -0,0 +1,164 @@
+/*
+ Copyright (c) 2017, 2019, MariaDB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include <my_global.h>
+#include <sys/statvfs.h>
+#include <sys/types.h>
+#include <mntent.h>
+#include <sql_class.h>
+#include <sql_i_s.h>
+#include <sql_acl.h> /* check_global_access() */
+
+bool schema_table_store_record(THD *thd, TABLE *table);
+
+
+struct st_mysql_information_schema disks_table_info = { MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+
+namespace Show {
+
+ST_FIELD_INFO disks_table_fields[]=
+{
+ Column("Disk", Varchar(PATH_MAX), NOT_NULL),
+ Column("Path", Varchar(PATH_MAX), NOT_NULL),
+ Column("Total", SLonglong(32), NOT_NULL), // Total amount available
+ Column("Used", SLonglong(32), NOT_NULL), // Amount of space used
+ Column("Available", SLonglong(32), NOT_NULL), // Amount available to users other than root.
+ CEnd()
+};
+
+
+
+int disks_table_add_row(THD* pThd,
+ TABLE* pTable,
+ const char* zDisk,
+ const char* zPath,
+ const struct statvfs& info)
+{
+ // From: http://pubs.opengroup.org/onlinepubs/009695399/basedefs/sys/statvfs.h.html
+ //
+ // f_frsize Fundamental file system block size.
+ // f_blocks Total number of blocks on file system in units of f_frsize.
+ // f_bfree Total number of free blocks.
+ // f_bavail Number of free blocks available to non-privileged process.
+
+ ulonglong total = ((ulonglong)info.f_frsize * info.f_blocks) / 1024;
+ ulonglong used = ((ulonglong)info.f_frsize *
+ (info.f_blocks - info.f_bfree)) / 1024;
+ ulonglong avail = ((ulonglong)info.f_frsize * info.f_bavail) / 1024;
+
+ pTable->field[0]->store(zDisk, strlen(zDisk), system_charset_info);
+ pTable->field[1]->store(zPath, strlen(zPath), system_charset_info);
+ pTable->field[2]->store(total);
+ pTable->field[3]->store(used);
+ pTable->field[4]->store(avail);
+
+ // 0 means success.
+ return (schema_table_store_record(pThd, pTable) != 0) ? 1 : 0;
+}
+
+int disks_table_add_row(THD* pThd, TABLE* pTable, const char* zDisk, const char* zPath)
+{
+ int rv = 0;
+
+ struct statvfs info;
+
+ if (statvfs(zPath, &info) == 0) // We ignore failures.
+ {
+ rv = disks_table_add_row(pThd, pTable, zDisk, zPath, info);
+ }
+
+ return rv;
+}
+
+int disks_fill_table(THD* pThd, TABLE_LIST* pTables, Item* pCond)
+{
+ int rv = 1;
+ TABLE* pTable = pTables->table;
+
+ if (check_global_access(pThd, FILE_ACL, true))
+ return 0;
+
+ FILE* pFile = setmntent("/etc/mtab", "r");
+
+ if (pFile)
+ {
+ const size_t BUFFER_SIZE = 4096; // 4K should be sufficient.
+
+ char* pBuffer = new (std::nothrow) char [BUFFER_SIZE];
+
+ if (pBuffer)
+ {
+ rv = 0;
+
+ struct mntent ent;
+ struct mntent* pEnt;
+
+ while ((rv == 0) && (pEnt = getmntent_r(pFile, &ent, pBuffer, BUFFER_SIZE)))
+ {
+ // We only report the ones that refer to physical disks.
+ if (pEnt->mnt_fsname[0] == '/')
+ {
+ rv = disks_table_add_row(pThd, pTable, pEnt->mnt_fsname, pEnt->mnt_dir);
+ }
+ }
+
+ delete [] pBuffer;
+ }
+ else
+ {
+ rv = 1;
+ }
+
+ endmntent(pFile);
+ }
+
+ return rv;
+}
+
+int disks_table_init(void *ptr)
+{
+ ST_SCHEMA_TABLE* pSchema_table = (ST_SCHEMA_TABLE*)ptr;
+
+ pSchema_table->fields_info = disks_table_fields;
+ pSchema_table->fill_table = disks_fill_table;
+ return 0;
+}
+
+} // namespace Show
+
+extern "C"
+{
+
+maria_declare_plugin(disks)
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &disks_table_info, /* type-specific descriptor */
+ "DISKS", /* table name */
+ "Johan Wikman", /* author */
+ "Disk space information", /* description */
+ PLUGIN_LICENSE_GPL, /* license type */
+ Show::disks_table_init, /* init function */
+ NULL, /* deinit function */
+ 0x0101, /* version = 1.1 */
+ NULL, /* no status variables */
+ NULL, /* no system variables */
+ "1.1", /* String version representation */
+ MariaDB_PLUGIN_MATURITY_STABLE /* Maturity (see include/mysql/plugin.h)*/
+}
+mysql_declare_plugin_end;
+
+}
diff --git a/plugin/disks/mysql-test/disks/disks.result b/plugin/disks/mysql-test/disks/disks.result
new file mode 100644
index 00000000..0b4ee624
--- /dev/null
+++ b/plugin/disks/mysql-test/disks/disks.result
@@ -0,0 +1,12 @@
+show create table information_schema.disks;
+Table Create Table
+DISKS CREATE TEMPORARY TABLE `DISKS` (
+ `Disk` varchar(4096) NOT NULL DEFAULT '',
+ `Path` varchar(4096) NOT NULL DEFAULT '',
+ `Total` bigint(32) NOT NULL DEFAULT 0,
+ `Used` bigint(32) NOT NULL DEFAULT 0,
+ `Available` bigint(32) NOT NULL DEFAULT 0
+) ENGINE=MEMORY DEFAULT CHARSET=utf8
+select sum(Total) > sum(Available), sum(Total)>sum(Used) from information_schema.disks;
+sum(Total) > sum(Available) sum(Total)>sum(Used)
+1 1
diff --git a/plugin/disks/mysql-test/disks/disks.test b/plugin/disks/mysql-test/disks/disks.test
new file mode 100644
index 00000000..13a0762a
--- /dev/null
+++ b/plugin/disks/mysql-test/disks/disks.test
@@ -0,0 +1,2 @@
+show create table information_schema.disks;
+select sum(Total) > sum(Available), sum(Total)>sum(Used) from information_schema.disks;
diff --git a/plugin/disks/mysql-test/disks/disks_notembedded.result b/plugin/disks/mysql-test/disks/disks_notembedded.result
new file mode 100644
index 00000000..97429474
--- /dev/null
+++ b/plugin/disks/mysql-test/disks/disks_notembedded.result
@@ -0,0 +1,22 @@
+#
+# MDEV-18328: Make DISKS plugin check some privilege to access
+# information_schema.DISKS table
+#
+CREATE USER user1@localhost;
+GRANT SELECT ON *.* TO user1@localhost;
+connect con1,localhost,user1,,;
+connection con1;
+select sum(Total) > sum(Available), sum(Total)>sum(Used) from information_schema.disks;
+sum(Total) > sum(Available) sum(Total)>sum(Used)
+NULL NULL
+disconnect con1;
+connection default;
+GRANT FILE ON *.* TO user1@localhost;
+connect con1,localhost,user1,,;
+connection con1;
+select sum(Total) > sum(Available), sum(Total)>sum(Used) from information_schema.disks;
+sum(Total) > sum(Available) sum(Total)>sum(Used)
+1 1
+connection default;
+DROP USER user1@localhost;
+# End of 10.1 tests
diff --git a/plugin/disks/mysql-test/disks/disks_notembedded.test b/plugin/disks/mysql-test/disks/disks_notembedded.test
new file mode 100644
index 00000000..a0f6c2e5
--- /dev/null
+++ b/plugin/disks/mysql-test/disks/disks_notembedded.test
@@ -0,0 +1,25 @@
+source include/not_embedded.inc;
+
+--echo #
+--echo # MDEV-18328: Make DISKS plugin check some privilege to access
+--echo # information_schema.DISKS table
+--echo #
+
+CREATE USER user1@localhost;
+GRANT SELECT ON *.* TO user1@localhost;
+
+connect (con1,localhost,user1,,);
+connection con1;
+select sum(Total) > sum(Available), sum(Total)>sum(Used) from information_schema.disks;
+disconnect con1;
+
+connection default;
+GRANT FILE ON *.* TO user1@localhost;
+
+connect (con1,localhost,user1,,);
+connection con1;
+select sum(Total) > sum(Available), sum(Total)>sum(Used) from information_schema.disks;
+connection default;
+DROP USER user1@localhost;
+
+--echo # End of 10.1 tests
diff --git a/plugin/disks/mysql-test/disks/suite.opt b/plugin/disks/mysql-test/disks/suite.opt
new file mode 100644
index 00000000..afbbe2b0
--- /dev/null
+++ b/plugin/disks/mysql-test/disks/suite.opt
@@ -0,0 +1 @@
+--plugin-load-add=$DISKS_SO
diff --git a/plugin/disks/mysql-test/disks/suite.pm b/plugin/disks/mysql-test/disks/suite.pm
new file mode 100644
index 00000000..c64ef3b3
--- /dev/null
+++ b/plugin/disks/mysql-test/disks/suite.pm
@@ -0,0 +1,10 @@
+package My::Suite::Disks;
+
+@ISA = qw(My::Suite);
+
+return "No Disks plugin" unless $ENV{DISKS_SO};
+
+sub is_default { 1 }
+
+bless { };
+
diff --git a/plugin/example_key_management/CMakeLists.txt b/plugin/example_key_management/CMakeLists.txt
new file mode 100644
index 00000000..fe893e53
--- /dev/null
+++ b/plugin/example_key_management/CMakeLists.txt
@@ -0,0 +1,2 @@
+MYSQL_ADD_PLUGIN(EXAMPLE_KEY_MANAGEMENT example_key_management_plugin.cc
+ MODULE_ONLY COMPONENT Test)
diff --git a/plugin/example_key_management/example_key_management_plugin.cc b/plugin/example_key_management/example_key_management_plugin.cc
new file mode 100644
index 00000000..665e3128
--- /dev/null
+++ b/plugin/example_key_management/example_key_management_plugin.cc
@@ -0,0 +1,170 @@
+/*
+ Copyright (c) 2014 Google Inc.
+ Copyright (c) 2014, 2015 MariaDB Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/**
+ Example key management plugin. It demonstrates how to return
+ keys on request, how to change them. That the engine can have
+ different pages in the same tablespace encrypted with different keys
+ and what the background re-encryption thread does.
+
+ THIS IS AN EXAMPLE ONLY! ENCRYPTION KEYS ARE HARD-CODED AND *NOT* SECRET!
+ DO NOT USE THIS PLUGIN IN PRODUCTION! EVER!
+*/
+
+#include <my_global.h>
+#include <my_pthread.h>
+#include <mysql/plugin_encryption.h>
+#include <my_crypt.h>
+
+/* rotate key randomly between 45 and 90 seconds */
+#define KEY_ROTATION_MIN 45
+#define KEY_ROTATION_MAX 90
+
+static time_t key_version = 0;
+static time_t next_key_version = 0;
+static pthread_mutex_t mutex;
+
+
+/* Random double value in 0..1 range */
+static double double_rnd()
+{
+ return ((double)rand()) / RAND_MAX;
+}
+
+
+static unsigned int
+get_latest_key_version(unsigned int key_id)
+{
+ time_t now = time(0);
+ pthread_mutex_lock(&mutex);
+ if (now >= next_key_version)
+ {
+ key_version = now;
+ unsigned int interval = KEY_ROTATION_MAX - KEY_ROTATION_MIN;
+ next_key_version = (time_t) (now + KEY_ROTATION_MIN +
+ double_rnd() * interval);
+ }
+ pthread_mutex_unlock(&mutex);
+
+ return (unsigned int) key_version;
+}
+
+static unsigned int
+get_key(unsigned int key_id, unsigned int version,
+ unsigned char* dstbuf, unsigned *buflen)
+{
+ if (*buflen < MY_MD5_HASH_SIZE)
+ {
+ *buflen= MY_MD5_HASH_SIZE;
+ return ENCRYPTION_KEY_BUFFER_TOO_SMALL;
+ }
+ *buflen= MY_MD5_HASH_SIZE;
+ if (!dstbuf)
+ return 0;
+
+ my_md5_multi(dstbuf, (const char*)&key_id, sizeof(key_id),
+ (const char*)&version, sizeof(version), NULL);
+
+ return 0;
+}
+
+/*
+ for the sake of an example, let's use different encryption algorithms/modes
+ for different keys versions:
+*/
+static inline enum my_aes_mode mode(unsigned int key_version)
+{
+ return key_version & 1 ? MY_AES_ECB : MY_AES_CBC;
+}
+
+int ctx_init(void *ctx, const unsigned char* key, unsigned int klen, const
+ unsigned char* iv, unsigned int ivlen, int flags, unsigned int
+ key_id, unsigned int key_version)
+{
+ return my_aes_crypt_init(ctx, mode(key_version), flags, key, klen, iv, ivlen);
+}
+
+static unsigned int get_length(unsigned int slen, unsigned int key_id,
+ unsigned int key_version)
+{
+ return my_aes_get_size(mode(key_version), slen);
+}
+
+static int example_key_management_plugin_init(void *p)
+{
+ /* init */
+ pthread_mutex_init(&mutex, NULL);
+ get_latest_key_version(1);
+
+ return 0;
+}
+
+static int example_key_management_plugin_deinit(void *p)
+{
+ pthread_mutex_destroy(&mutex);
+ return 0;
+}
+
+
+static int ctx_update(void *ctx, const unsigned char *src, unsigned int slen,
+ unsigned char *dst, unsigned int *dlen)
+{
+ return my_aes_crypt_update(ctx, src, slen, dst, dlen);
+}
+
+
+int ctx_finish(void *ctx, unsigned char *dst, unsigned int *dlen)
+{
+ return my_aes_crypt_finish(ctx, dst, dlen);
+}
+
+static uint ctx_size(unsigned int , unsigned int key_version)
+{
+ return my_aes_ctx_size(mode(key_version));
+}
+
+struct st_mariadb_encryption example_key_management_plugin= {
+ MariaDB_ENCRYPTION_INTERFACE_VERSION,
+ get_latest_key_version,
+ get_key,
+ ctx_size,
+ ctx_init,
+ ctx_update,
+ ctx_finish,
+ get_length
+};
+
+/*
+ Plugin library descriptor
+*/
+maria_declare_plugin(example_key_management)
+{
+ MariaDB_ENCRYPTION_PLUGIN,
+ &example_key_management_plugin,
+ "example_key_management",
+ "Jonas Oreland",
+ "Example key management plugin",
+ PLUGIN_LICENSE_GPL,
+ example_key_management_plugin_init,
+ example_key_management_plugin_deinit,
+ 0x0100 /* 1.0 */,
+ NULL, /* status variables */
+ NULL, /* system variables */
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_EXPERIMENTAL
+}
+maria_declare_plugin_end;
diff --git a/plugin/feedback/CMakeLists.txt b/plugin/feedback/CMakeLists.txt
new file mode 100644
index 00000000..2103250e
--- /dev/null
+++ b/plugin/feedback/CMakeLists.txt
@@ -0,0 +1,23 @@
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql
+ ${PCRE_INCLUDES}
+ ${SSL_INCLUDE_DIRS})
+
+SET(FEEDBACK_SOURCES feedback.cc sender_thread.cc
+ url_base.cc url_http.cc utils.cc)
+
+ADD_DEFINITIONS(${SSL_DEFINES})
+
+INCLUDE (CheckIncludeFiles)
+CHECK_INCLUDE_FILES (netdb.h HAVE_NETDB_H)
+IF(HAVE_NETDB_H)
+ ADD_DEFINITIONS(-DHAVE_NETDB_H)
+ENDIF(HAVE_NETDB_H)
+
+IF(WIN32)
+ SET(MAYBE_STATIC_ONLY STATIC_ONLY)
+ENDIF(WIN32)
+
+MYSQL_ADD_PLUGIN(FEEDBACK ${FEEDBACK_SOURCES}
+ LINK_LIBRARIES ${SSL_LIBRARIES}
+ ${MAYBE_STATIC_ONLY} RECOMPILE_FOR_EMBEDDED DEFAULT)
+
diff --git a/plugin/feedback/feedback.cc b/plugin/feedback/feedback.cc
new file mode 100644
index 00000000..eb3f562f
--- /dev/null
+++ b/plugin/feedback/feedback.cc
@@ -0,0 +1,428 @@
+/* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "feedback.h"
+
+/* MySQL functions/variables not declared in mysql_priv.h */
+int fill_variables(THD *thd, TABLE_LIST *tables, COND *cond);
+int fill_status(THD *thd, TABLE_LIST *tables, COND *cond);
+extern ST_SCHEMA_TABLE schema_tables[];
+
+namespace feedback {
+
+#ifndef DBUG_OFF
+ulong debug_startup_interval, debug_first_interval, debug_interval;
+#endif
+
+char server_uid_buf[SERVER_UID_SIZE+1]; ///< server uid will be written here
+
+/* backing store for system variables */
+static char *server_uid= server_uid_buf, *url, *http_proxy;
+char *user_info;
+ulong send_timeout, send_retry_wait;
+
+/**
+ these three are used to communicate the shutdown signal to the
+ background thread
+*/
+mysql_mutex_t sleep_mutex;
+mysql_cond_t sleep_condition;
+volatile bool shutdown_plugin;
+static pthread_t sender_thread;
+
+#ifdef HAVE_PSI_INTERFACE
+static PSI_mutex_key key_sleep_mutex;
+static PSI_mutex_info mutex_list[]=
+{{ &key_sleep_mutex, "sleep_mutex", PSI_FLAG_GLOBAL}};
+
+static PSI_cond_key key_sleep_cond;
+static PSI_cond_info cond_list[]=
+{{ &key_sleep_cond, "sleep_condition", PSI_FLAG_GLOBAL}};
+
+static PSI_thread_key key_sender_thread;
+static PSI_thread_info thread_list[] =
+{{&key_sender_thread, "sender_thread", 0}};
+#endif
+
+Url **urls; ///< list of urls to send the report to
+uint url_count;
+
+ST_SCHEMA_TABLE *i_s_feedback; ///< table descriptor for our I_S table
+
+/*
+ the column names *must* match column names in GLOBAL_VARIABLES and
+ GLOBAL_STATUS tables otherwise condition pushdown below will not work
+*/
+static ST_FIELD_INFO feedback_fields[] =
+{
+ Show::Column("VARIABLE_NAME", Show::Varchar(255), NOT_NULL),
+ Show::Column("VARIABLE_VALUE", Show::Varchar(1024), NOT_NULL),
+ Show::CEnd()
+};
+
+static COND * const OOM= (COND*)1;
+
+/**
+ Generate the COND tree for the condition pushdown
+
+ This function takes a list of strings and generates an Item tree
+ corresponding to the following expression:
+
+ field LIKE str1 OR field LIKE str2 OR field LIKE str3 OR ...
+
+ where 'field' is the first field in the table - VARIABLE_NAME field -
+ and str1, str2... are strings from the list.
+
+ This condition is used to filter the selected rows, emulating
+
+ SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE ...
+*/
+static COND* make_cond(THD *thd, TABLE_LIST *tables, LEX_STRING *filter)
+{
+ Item_cond_or *res= NULL;
+ Name_resolution_context nrc;
+ LEX_CSTRING &db= tables->db;
+ LEX_CSTRING &table= tables->alias;
+ LEX_CSTRING &field= tables->table->field[0]->field_name;
+ CHARSET_INFO *cs= &my_charset_latin1;
+
+ if (!filter->str)
+ return 0;
+
+ nrc.init();
+ nrc.resolve_in_table_list_only(tables);
+
+ res= new (thd->mem_root) Item_cond_or(thd);
+ if (!res)
+ return OOM;
+
+ for (; filter->str; filter++)
+ {
+ Item_field *fld= new (thd->mem_root) Item_field(thd, &nrc, db, table,
+ field);
+ Item_string *pattern= new (thd->mem_root) Item_string(thd, filter->str,
+ (uint) filter->length, cs);
+ Item_string *escape= new (thd->mem_root) Item_string(thd, "\\", 1, cs);
+
+ if (!fld || !pattern || !escape)
+ return OOM;
+
+ Item_func_like *like= new (thd->mem_root) Item_func_like(thd, fld, pattern,
+ escape, 0);
+
+ if (!like)
+ return OOM;
+
+ res->add(like, thd->mem_root);
+ }
+
+ if (res->fix_fields(thd, (Item**)&res))
+ return OOM;
+
+ return res;
+}
+
+/**
+ System variables that we want to see in the feedback report
+*/
+static LEX_STRING vars_filter[]= {
+ {C_STRING_WITH_LEN("auto\\_increment%")},
+ {C_STRING_WITH_LEN("binlog\\_format")},
+ {C_STRING_WITH_LEN("character\\_set\\_%")},
+ {C_STRING_WITH_LEN("collation%")},
+ {C_STRING_WITH_LEN("engine\\_condition\\_pushdown")},
+ {C_STRING_WITH_LEN("event\\_scheduler")},
+ {C_STRING_WITH_LEN("feedback\\_%")},
+ {C_STRING_WITH_LEN("ft\\_m%")},
+ {C_STRING_WITH_LEN("have\\_%")},
+ {C_STRING_WITH_LEN("%\\_size")},
+ {C_STRING_WITH_LEN("innodb_f%")},
+ {C_STRING_WITH_LEN("%\\_length%")},
+ {C_STRING_WITH_LEN("%\\_timeout")},
+ {C_STRING_WITH_LEN("large\\_%")},
+ {C_STRING_WITH_LEN("lc_time_names")},
+ {C_STRING_WITH_LEN("log")},
+ {C_STRING_WITH_LEN("log_bin")},
+ {C_STRING_WITH_LEN("log_output")},
+ {C_STRING_WITH_LEN("log_slow_queries")},
+ {C_STRING_WITH_LEN("log_slow_time")},
+ {C_STRING_WITH_LEN("lower_case%")},
+ {C_STRING_WITH_LEN("max_allowed_packet")},
+ {C_STRING_WITH_LEN("max_connections")},
+ {C_STRING_WITH_LEN("max_prepared_stmt_count")},
+ {C_STRING_WITH_LEN("max_sp_recursion_depth")},
+ {C_STRING_WITH_LEN("max_user_connections")},
+ {C_STRING_WITH_LEN("max_write_lock_count")},
+ {C_STRING_WITH_LEN("myisam_recover_options")},
+ {C_STRING_WITH_LEN("myisam_repair_threads")},
+ {C_STRING_WITH_LEN("myisam_stats_method")},
+ {C_STRING_WITH_LEN("myisam_use_mmap")},
+ {C_STRING_WITH_LEN("net\\_%")},
+ {C_STRING_WITH_LEN("new")},
+ {C_STRING_WITH_LEN("old%")},
+ {C_STRING_WITH_LEN("optimizer%")},
+ {C_STRING_WITH_LEN("profiling")},
+ {C_STRING_WITH_LEN("query_cache%")},
+ {C_STRING_WITH_LEN("secure_auth")},
+ {C_STRING_WITH_LEN("slow_launch_time")},
+ {C_STRING_WITH_LEN("sql%")},
+ {C_STRING_WITH_LEN("default_storage_engine")},
+ {C_STRING_WITH_LEN("sync_binlog")},
+ {C_STRING_WITH_LEN("table_definition_cache")},
+ {C_STRING_WITH_LEN("table_open_cache")},
+ {C_STRING_WITH_LEN("thread_handling")},
+ {C_STRING_WITH_LEN("time_zone")},
+ {C_STRING_WITH_LEN("version%")},
+ {0, 0}
+};
+
+/**
+ Status variables that we want to see in the feedback report
+
+ (empty list = no WHERE condition)
+*/
+static LEX_STRING status_filter[]= {{0, 0}};
+
+/**
+ Fill our I_S table with data
+
+ This function works by invoking fill_variables() and
+ fill_status() of the corresponding I_S tables - to have
+ their data UNION-ed in the same target table.
+ After that it invokes our own fill_* functions
+ from the utils.cc - to get the data that aren't available in the
+ I_S.GLOBAL_VARIABLES and I_S.GLOBAL_STATUS.
+*/
+int fill_feedback(THD *thd, TABLE_LIST *tables, COND *unused)
+{
+ int res;
+ COND *cond;
+
+ tables->schema_table= schema_tables + SCH_GLOBAL_VARIABLES;
+ cond= make_cond(thd, tables, vars_filter);
+ res= (cond == OOM) ? 1 : fill_variables(thd, tables, cond);
+
+ tables->schema_table= schema_tables + SCH_GLOBAL_STATUS;
+ if (!res)
+ {
+ cond= make_cond(thd, tables, status_filter);
+ res= (cond == OOM) ? 1 : fill_status(thd, tables, cond);
+ }
+
+ tables->schema_table= i_s_feedback;
+ res= res || fill_plugin_version(thd, tables)
+ || fill_misc_data(thd, tables)
+ || fill_linux_info(thd, tables)
+ || fill_collation_statistics(thd, tables);
+
+ return res;
+}
+
+/**
+ plugin initialization function
+*/
+static int init(void *p)
+{
+ i_s_feedback= (ST_SCHEMA_TABLE*) p;
+ /* initialize the I_S descriptor structure */
+ i_s_feedback->fields_info= feedback_fields; ///< field descriptor
+ i_s_feedback->fill_table= fill_feedback; ///< how to fill the I_S table
+ i_s_feedback->idx_field1 = 0; ///< virtual index on the 1st col
+
+#ifdef HAVE_PSI_INTERFACE
+#define PSI_register(X) \
+ if(PSI_server) PSI_server->register_ ## X("feedback", X ## _list, array_elements(X ## _list))
+#else
+#define PSI_register(X) /* no-op */
+#endif
+
+ PSI_register(mutex);
+ PSI_register(cond);
+ PSI_register(thread);
+
+ if (calculate_server_uid(server_uid_buf))
+ return 1;
+
+ prepare_linux_info();
+
+#ifndef DBUG_OFF
+ if (startup_interval != debug_startup_interval ||
+ first_interval != debug_first_interval ||
+ interval != debug_interval)
+ {
+ startup_interval= debug_startup_interval;
+ first_interval= debug_first_interval;
+ interval= debug_interval;
+ user_info= const_cast<char*>("mysql-test");
+ }
+#endif
+
+ url_count= 0;
+ if (*url)
+ {
+ // now we split url on spaces and store them in Url objects
+ int slot;
+ char *s, *e;
+
+ for (s= url, url_count= 1; *s; s++)
+ if (*s == ' ')
+ url_count++;
+
+ urls= (Url **)my_malloc(PSI_INSTRUMENT_ME, url_count*sizeof(Url*), MYF(MY_WME));
+ if (!urls)
+ return 1;
+
+ for (s= url, e = url+1, slot= 0; e[-1]; e++)
+ if (*e == 0 || *e == ' ')
+ {
+ if (e > s && (urls[slot]= Url::create(s, e - s)))
+ {
+ if (urls[slot]->set_proxy(http_proxy,
+ http_proxy ? strlen(http_proxy) : 0))
+ sql_print_error("feedback plugin: invalid proxy '%s'",
+ http_proxy ? http_proxy : "");
+ slot++;
+ }
+ else
+ {
+ if (e > s)
+ sql_print_error("feedback plugin: invalid url '%.*s'", (int)(e-s), s);
+ url_count--;
+ }
+ s= e + 1;
+ }
+
+ // create a background thread to handle urls, if any
+ if (url_count)
+ {
+ mysql_mutex_init(0, &sleep_mutex, 0);
+ mysql_cond_init(0, &sleep_condition, 0);
+ shutdown_plugin= false;
+
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+ if (pthread_create(&sender_thread, &attr, background_thread, 0) != 0)
+ {
+ sql_print_error("feedback plugin: failed to start a background thread");
+ return 1;
+ }
+ }
+ else
+ my_free(urls);
+ }
+
+ return 0;
+}
+
+/**
+ plugin deinitialization function
+*/
+static int free(void *p)
+{
+ if (url_count)
+ {
+ mysql_mutex_lock(&sleep_mutex);
+ shutdown_plugin= true;
+ mysql_cond_signal(&sleep_condition);
+ mysql_mutex_unlock(&sleep_mutex);
+ pthread_join(sender_thread, NULL);
+
+ mysql_mutex_destroy(&sleep_mutex);
+ mysql_cond_destroy(&sleep_condition);
+
+ for (uint i= 0; i < url_count; i++)
+ delete urls[i];
+ my_free(urls);
+ }
+ return 0;
+}
+
+#ifdef HAVE_OPENSSL
+#define DEFAULT_PROTO "https://"
+#else
+#define DEFAULT_PROTO "http://"
+#endif
+
+static MYSQL_SYSVAR_STR(server_uid, server_uid,
+ PLUGIN_VAR_READONLY | PLUGIN_VAR_NOCMDOPT,
+ "Automatically calculated server unique id hash.", NULL, NULL, 0);
+static MYSQL_SYSVAR_STR(user_info, user_info,
+ PLUGIN_VAR_READONLY | PLUGIN_VAR_RQCMDARG,
+ "User specified string that will be included in the feedback report.",
+ NULL, NULL, "");
+static MYSQL_SYSVAR_STR(url, url, PLUGIN_VAR_READONLY | PLUGIN_VAR_RQCMDARG,
+ "Space separated URLs to send the feedback report to.", NULL, NULL,
+ DEFAULT_PROTO "mariadb.org/feedback_plugin/post");
+static MYSQL_SYSVAR_ULONG(send_timeout, send_timeout, PLUGIN_VAR_RQCMDARG,
+ "Timeout (in seconds) for the sending the report.",
+ NULL, NULL, 60, 1, 60*60*24, 1);
+static MYSQL_SYSVAR_ULONG(send_retry_wait, send_retry_wait, PLUGIN_VAR_RQCMDARG,
+ "Wait this many seconds before retrying a failed send.",
+ NULL, NULL, 60, 1, 60*60*24, 1);
+static MYSQL_SYSVAR_STR(http_proxy, http_proxy,
+ PLUGIN_VAR_READONLY | PLUGIN_VAR_RQCMDARG,
+ "Proxy server host:port.", NULL, NULL,0);
+
+#ifndef DBUG_OFF
+static MYSQL_SYSVAR_ULONG(debug_startup_interval, debug_startup_interval,
+ PLUGIN_VAR_RQCMDARG, "for debugging only",
+ NULL, NULL, startup_interval, 1, INT_MAX32, 1);
+static MYSQL_SYSVAR_ULONG(debug_first_interval, debug_first_interval,
+ PLUGIN_VAR_RQCMDARG, "for debugging only",
+ NULL, NULL, first_interval, 1, INT_MAX32, 1);
+static MYSQL_SYSVAR_ULONG(debug_interval, debug_interval,
+ PLUGIN_VAR_RQCMDARG, "for debugging only",
+ NULL, NULL, interval, 1, INT_MAX32, 1);
+#endif
+
+static struct st_mysql_sys_var* settings[] = {
+ MYSQL_SYSVAR(server_uid),
+ MYSQL_SYSVAR(user_info),
+ MYSQL_SYSVAR(url),
+ MYSQL_SYSVAR(send_timeout),
+ MYSQL_SYSVAR(send_retry_wait),
+ MYSQL_SYSVAR(http_proxy),
+#ifndef DBUG_OFF
+ MYSQL_SYSVAR(debug_startup_interval),
+ MYSQL_SYSVAR(debug_first_interval),
+ MYSQL_SYSVAR(debug_interval),
+#endif
+ NULL
+};
+
+
+static struct st_mysql_information_schema feedback =
+{ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+} // namespace feedback
+
+maria_declare_plugin(feedback)
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &feedback::feedback,
+ "FEEDBACK",
+ "Sergei Golubchik",
+ "MariaDB User Feedback Plugin",
+ PLUGIN_LICENSE_GPL,
+ feedback::init,
+ feedback::free,
+ 0x0101,
+ NULL,
+ feedback::settings,
+ "1.1",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
diff --git a/plugin/feedback/feedback.h b/plugin/feedback/feedback.h
new file mode 100644
index 00000000..04fe1ab6
--- /dev/null
+++ b/plugin/feedback/feedback.h
@@ -0,0 +1,79 @@
+/* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#define MYSQL_SERVER 1
+#include <my_global.h>
+#include <sql_class.h>
+
+namespace feedback {
+
+int fill_feedback(THD *thd, TABLE_LIST *tables, COND *cond);
+int fill_plugin_version(THD *thd, TABLE_LIST *tables);
+int fill_misc_data(THD *thd, TABLE_LIST *tables);
+int fill_linux_info(THD *thd, TABLE_LIST *tables);
+int fill_collation_statistics(THD *thd, TABLE_LIST *tables);
+
+static const int SERVER_UID_SIZE= 29;
+extern char server_uid_buf[SERVER_UID_SIZE+1], *user_info;
+int calculate_server_uid(char *);
+int prepare_linux_info();
+
+extern ST_SCHEMA_TABLE *i_s_feedback;
+
+extern ulong send_timeout, send_retry_wait;
+
+pthread_handler_t background_thread(void *arg);
+
+/**
+ The class for storing urls to send report data to.
+
+ Constructors are private, the object should be created with create() method.
+ send() method does the actual sending.
+*/
+class Url {
+ protected:
+ Url(LEX_STRING &url_arg) : full_url(url_arg) {}
+ const LEX_STRING full_url;
+
+ public:
+ virtual ~Url() { my_free(full_url.str); }
+
+ const char *url() { return full_url.str; }
+ size_t url_length() { return full_url.length; }
+ virtual int send(const char* data, size_t data_length) = 0;
+ virtual int set_proxy(const char *proxy, size_t proxy_len)
+ {
+ return 0;
+ }
+
+ static Url* create(const char *url, size_t url_length);
+ static int parse_proxy_server(const char *proxy_server, size_t proxy_length,
+ LEX_STRING *host, LEX_STRING *port);
+};
+
+extern Url **urls;
+extern uint url_count;
+
+extern ulong startup_interval;
+extern ulong first_interval;
+extern ulong interval;
+
+/* these are used to communicate with the background thread */
+extern mysql_mutex_t sleep_mutex;
+extern mysql_cond_t sleep_condition;
+extern volatile bool shutdown_plugin;
+
+} // namespace feedback
+
diff --git a/plugin/feedback/sender_thread.cc b/plugin/feedback/sender_thread.cc
new file mode 100644
index 00000000..73b1bc67
--- /dev/null
+++ b/plugin/feedback/sender_thread.cc
@@ -0,0 +1,298 @@
+/* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "feedback.h"
+#include <sql_acl.h>
+#include <sql_parse.h>
+#include <sql_show.h>
+#include <time.h>
+
+namespace feedback {
+
+static THD *thd= 0; ///< background thread thd
+static my_thread_id thd_thread_id; ///< its thread_id
+
+static size_t needed_size= 20480;
+
+ulong startup_interval= 60*5; ///< in seconds (5 minutes)
+ulong first_interval= 60*60*24; ///< in seconds (one day)
+ulong interval= 60*60*24*7; ///< in seconds (one week)
+
+/**
+ reads the rows from a table and puts them, concatenated, in a String
+
+ @note
+ 1. only supports two column tables - no less, no more.
+ 2. it emulates mysql -e "select * from..." and thus it separates
+ columns with \t and starts the output with column names.
+*/
+static int table_to_string(TABLE *table, String *result)
+{
+ int res;
+ char buff1[MAX_FIELD_WIDTH], buff2[MAX_FIELD_WIDTH];
+ String str1(buff1, sizeof(buff1), system_charset_info);
+ String str2(buff2, sizeof(buff2), system_charset_info);
+
+ res= table->file->ha_rnd_init(1);
+
+ dbug_tmp_use_all_columns(table, &table->read_set);
+
+ while(!res && !table->file->ha_rnd_next(table->record[0]))
+ {
+ table->field[0]->val_str(&str1);
+ table->field[1]->val_str(&str2);
+ if (result->reserve(str1.length() + str2.length() + 3))
+ res= 1;
+ else
+ {
+ result->qs_append(str1.ptr(), str1.length());
+ result->qs_append('\t');
+ result->qs_append(str2.ptr(), str2.length());
+ result->qs_append('\n');
+ }
+ }
+
+ res = res || (int)result->append('\n');
+
+ /*
+ Note, "|=" and not "||" - because we want to call ha_rnd_end()
+ even if res is already 1.
+ */
+ res |= table->file->ha_rnd_end();
+
+ return res;
+}
+
+/**
+ Initialize the THD and TABLE_LIST
+
+ The structures must be sufficiently initialized for create_tmp_table()
+ and fill_feedback() to work.
+*/
+static int prepare_for_fill(TABLE_LIST *tables)
+{
+ /*
+ Add our thd to the list, for it to be visible in SHOW PROCESSLIST.
+ But don't generate thread_id every time - use the saved value
+ (every increment of global thread_id counts as a new connection
+ in SHOW STATUS and we want to avoid skewing the statistics)
+ */
+ thd->variables.pseudo_thread_id= thd->thread_id;
+ server_threads.insert(thd);
+ thd->thread_stack= (char*) &tables;
+ thd->store_globals();
+
+ thd->mysys_var->current_cond= &sleep_condition;
+ thd->mysys_var->current_mutex= &sleep_mutex;
+ thd->proc_info="feedback";
+ thd->set_command(COM_SLEEP);
+ thd->system_thread= SYSTEM_THREAD_EVENT_WORKER; // whatever
+ thd->set_time();
+ thd->init_for_queries();
+ thd->real_id= pthread_self();
+ thd->db= null_clex_str;
+ thd->security_ctx->host_or_ip= "";
+ thd->security_ctx->db_access= DB_ACLS;
+ thd->security_ctx->master_access= ALL_KNOWN_ACL;
+ bzero((char*) &thd->net, sizeof(thd->net));
+ lex_start(thd);
+ mysql_init_select(thd->lex);
+
+ LEX_CSTRING tbl_name= {i_s_feedback->table_name, strlen(i_s_feedback->table_name) };
+
+ tables->init_one_table(&INFORMATION_SCHEMA_NAME, &tbl_name, 0, TL_READ);
+ tables->schema_table= i_s_feedback;
+ tables->schema_table_reformed= 1;
+ tables->select_lex= thd->lex->first_select_lex();
+ DBUG_ASSERT(tables->select_lex);
+ tables->table= create_schema_table(thd, tables);
+ if (!tables->table)
+ return 1;
+
+ tables->table->pos_in_table_list= tables;
+
+ return 0;
+}
+
+/**
+ Try to detect if this thread is going down
+
+ which can happen for different reasons:
+ * plugin is being unloaded
+ * mysqld server is being shut down
+ * the thread is being killed
+
+*/
+static bool going_down()
+{
+ return shutdown_plugin || abort_loop || (thd && thd->killed);
+}
+
+/**
+ just like sleep, but waits on a condition and checks "plugin shutdown" status
+*/
+static int slept_ok(time_t sec)
+{
+ struct timespec abstime;
+ int ret= 0;
+
+ set_timespec(abstime, sec);
+
+ mysql_mutex_lock(&sleep_mutex);
+ while (!going_down() && ret != ETIMEDOUT)
+ ret= mysql_cond_timedwait(&sleep_condition, &sleep_mutex, &abstime);
+ mysql_mutex_unlock(&sleep_mutex);
+
+ return !going_down();
+}
+
+/**
+ create a feedback report and send it to all specified urls
+
+ If "when" argument is not null, only it and the server uid are sent.
+ Otherwise a full report is generated.
+*/
+static void send_report(const char *when)
+{
+ TABLE_LIST tables;
+ String str;
+ int i, last_todo;
+ Url **todo= (Url**)alloca(url_count*sizeof(Url*));
+
+ str.alloc(needed_size); // preallocate it to avoid many small mallocs
+
+ /*
+ on startup and shutdown the server may not be completely
+ initialized, and full report won't work.
+ We send a short status notice only.
+ */
+ if (when)
+ {
+ str.length(0);
+ str.append(STRING_WITH_LEN("FEEDBACK_SERVER_UID"));
+ str.append('\t');
+ str.append(server_uid_buf);
+ str.append('\n');
+ str.append(STRING_WITH_LEN("FEEDBACK_WHEN"));
+ str.append('\t');
+ str.append(when);
+ str.append('\n');
+ str.append(STRING_WITH_LEN("FEEDBACK_USER_INFO"));
+ str.append('\t');
+ str.append(user_info);
+ str.append('\n');
+ str.append('\n');
+ }
+ else
+ {
+ /*
+ otherwise, prepare the THD and TABLE_LIST,
+ create and fill the temporary table with data just like
+ SELECT * FROM INFORMATION_SCHEMA.FEEDBACK is doing,
+ read and concatenate table data into a String.
+ */
+ if (!(thd= new THD(thd_thread_id)))
+ return;
+
+ if (prepare_for_fill(&tables))
+ goto ret;
+
+ if (fill_feedback(thd, &tables, NULL))
+ goto ret;
+
+ if (table_to_string(tables.table, &str))
+ goto ret;
+
+ needed_size= (size_t)(str.length() * 1.1);
+
+ free_tmp_table(thd, tables.table);
+ tables.table= 0;
+ }
+
+ /*
+ Try to send the report on every url from the list, remove url on success,
+ keep failed in the list. Repeat until the list is empty.
+ */
+ memcpy(todo, urls, url_count*sizeof(Url*));
+ last_todo= url_count - 1;
+ do
+ {
+ for (i= 0; i <= last_todo;)
+ {
+ Url *url= todo[i];
+
+ if (thd) // for nicer SHOW PROCESSLIST
+ thd->set_query(const_cast<char*>(url->url()), (uint) url->url_length());
+
+ if (url->send(str.ptr(), str.length()))
+ i++;
+ else
+ todo[i]= todo[last_todo--];
+ }
+ if (last_todo < 0)
+ break;
+ } while (slept_ok(send_retry_wait)); // wait a little bit before retrying
+
+ret:
+ if (thd)
+ {
+ if (tables.table)
+ free_tmp_table(thd, tables.table);
+ thd->cleanup_after_query();
+ /*
+ clean up, free the thd.
+ reset all thread local status variables to minimize
+ the effect of the background thread on SHOW STATUS.
+ */
+ server_threads.erase(thd);
+ thd->set_status_var_init();
+ thd->killed= KILL_CONNECTION;
+ delete thd;
+ thd= 0;
+ }
+}
+
+/**
+ background sending thread
+*/
+pthread_handler_t background_thread(void *arg __attribute__((unused)))
+{
+ if (my_thread_init())
+ return 0;
+
+ thd_thread_id= next_thread_id();
+
+ if (slept_ok(startup_interval))
+ {
+ send_report("startup");
+
+ if (slept_ok(first_interval))
+ {
+ send_report(NULL);
+
+ while(slept_ok(interval))
+ send_report(NULL);
+ }
+
+ send_report("shutdown");
+ }
+
+ my_thread_end();
+ pthread_exit(0);
+ return 0;
+}
+
+} // namespace feedback
+
diff --git a/plugin/feedback/url_base.cc b/plugin/feedback/url_base.cc
new file mode 100644
index 00000000..1ba21306
--- /dev/null
+++ b/plugin/feedback/url_base.cc
@@ -0,0 +1,96 @@
+/* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "feedback.h"
+
+namespace feedback {
+
+Url* http_create(const char *url, size_t url_length);
+
+/**
+ creates an Url object out of an url, if possible.
+
+ This is done by invoking corresponding creator functions
+ of the derived classes, until the first not NULL result.
+*/
+Url* Url::create(const char *url, size_t url_length)
+{
+ url= my_strndup(PSI_INSTRUMENT_ME, url, url_length, MYF(MY_WME));
+
+ if (!url)
+ return NULL;
+
+ Url *self= http_create(url, url_length);
+
+ /*
+ here we can add
+
+ if (!self) self= smtp_create(url, url_length);
+ if (!self) self= tftp_create(url, url_length);
+ etc
+ */
+
+ if (!self)
+ my_free(const_cast<char*>(url));
+
+ return self;
+}
+
+int Url::parse_proxy_server(const char *proxy_server, size_t proxy_length,
+ LEX_STRING *host, LEX_STRING *port)
+{
+ const char *s;
+
+ host->length= 0;
+ if (proxy_server == NULL)
+ return 0;
+
+ for (; proxy_length > 0 && my_isspace(system_charset_info, *proxy_server);
+ proxy_server++, proxy_length--) /* no-op */;
+
+ if (proxy_length == 0)
+ return 0;
+
+ for (s=proxy_server; *s && *s != ':'; s++) /* no-op */;
+
+ host->str= const_cast<char*>(proxy_server);
+ if ((host->length= s-proxy_server) == 0)
+ return 0;
+
+ port->length= 0;
+
+ if (*s == ':')
+ {
+ s++;
+ port->str= const_cast<char*>(s);
+ while (*s >= '0' && *s <= '9')
+ {
+ s++;
+ port->length++;
+ }
+ }
+
+ if (port->length == 0)
+ {
+ port->str= const_cast<char*>("80");
+ port->length= 2;
+ }
+
+ host->str= my_strndup(PSI_INSTRUMENT_ME, host->str, host->length, MYF(MY_WME));
+ port->str= my_strndup(PSI_INSTRUMENT_ME, port->str, port->length, MYF(MY_WME));
+ return 0;
+}
+
+} // namespace feedback
diff --git a/plugin/feedback/url_http.cc b/plugin/feedback/url_http.cc
new file mode 100644
index 00000000..98116dd0
--- /dev/null
+++ b/plugin/feedback/url_http.cc
@@ -0,0 +1,341 @@
+/* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "feedback.h"
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#ifdef _WIN32
+#include <ws2tcpip.h>
+#define addrinfo ADDRINFOA
+#endif
+
+namespace feedback {
+
+static const uint FOR_READING= 0;
+static const uint FOR_WRITING= 1;
+
+/**
+ implementation of the Url class that sends the data via HTTP POST request.
+
+ Both http:// and https:// protocols are supported.
+*/
+class Url_http: public Url {
+ protected:
+ const LEX_STRING host, port, path;
+ bool ssl;
+ LEX_STRING proxy_host, proxy_port;
+
+ bool use_proxy()
+ {
+ return proxy_host.length != 0;
+ }
+
+ Url_http(LEX_STRING &url_arg, LEX_STRING &host_arg,
+ LEX_STRING &port_arg, LEX_STRING &path_arg, bool ssl_arg) :
+ Url(url_arg), host(host_arg), port(port_arg), path(path_arg), ssl(ssl_arg)
+ {
+ proxy_host.length= 0;
+ }
+ ~Url_http()
+ {
+ my_free(host.str);
+ my_free(port.str);
+ my_free(path.str);
+ set_proxy(0,0);
+ }
+
+ public:
+ int send(const char* data, size_t data_length);
+ int set_proxy(const char *proxy, size_t proxy_len)
+ {
+ if (use_proxy())
+ {
+ my_free(proxy_host.str);
+ my_free(proxy_port.str);
+ }
+
+ return parse_proxy_server(proxy, proxy_len, &proxy_host, &proxy_port);
+ }
+
+ friend Url* http_create(const char *url, size_t url_length);
+};
+
+/**
+ create a Url_http object out of the url, if possible.
+
+ @note
+ Arbitrary limitations here.
+
+ The url must be http[s]://hostname[:port]/path
+ No username:password@ or ?script=parameters are supported.
+
+ But it's ok. This is not a generic purpose www browser - it only needs to be
+ good enough to POST the data to mariadb.org.
+*/
+Url* http_create(const char *url, size_t url_length)
+{
+ const char *s;
+ LEX_STRING full_url= {const_cast<char*>(url), url_length};
+ LEX_STRING host, port, path;
+ bool ssl= false;
+
+ if (is_prefix(url, "http://"))
+ s= url + 7;
+#ifdef HAVE_OPENSSL
+ else if (is_prefix(url, "https://"))
+ {
+ ssl= true;
+ s= url + 8;
+ }
+#endif
+ else
+ return NULL;
+
+ for (url= s; *s && *s != ':' && *s != '/'; s++) /* no-op */;
+ host.str= const_cast<char*>(url);
+ host.length= s-url;
+
+ if (*s == ':')
+ {
+ for (url= ++s; *s && *s >= '0' && *s <= '9'; s++) /* no-op */;
+ port.str= const_cast<char*>(url);
+ port.length= s-url;
+ }
+ else
+ {
+ if (ssl)
+ {
+ port.str= const_cast<char*>("443");
+ port.length=3;
+ }
+ else
+ {
+ port.str= const_cast<char*>("80");
+ port.length=2;
+ }
+ }
+
+ if (*s == 0)
+ {
+ path.str= const_cast<char*>("/");
+ path.length= 1;
+ }
+ else
+ {
+ path.str= const_cast<char*>(s);
+ path.length= strlen(s);
+ }
+ if (!host.length || !port.length || path.str[0] != '/')
+ return NULL;
+
+ host.str= my_strndup(PSI_INSTRUMENT_ME, host.str, host.length, MYF(MY_WME));
+ port.str= my_strndup(PSI_INSTRUMENT_ME, port.str, port.length, MYF(MY_WME));
+ path.str= my_strndup(PSI_INSTRUMENT_ME, path.str, path.length, MYF(MY_WME));
+
+ if (!host.str || !port.str || !path.str)
+ {
+ my_free(host.str);
+ my_free(port.str);
+ my_free(path.str);
+ return NULL;
+ }
+
+ return new Url_http(full_url, host, port, path, ssl);
+}
+
+/* do the vio_write and check that all data were sent ok */
+#define write_check(VIO, DATA, LEN) \
+ (vio_write((VIO), (uchar*)(DATA), (LEN)) != (LEN))
+
+int Url_http::send(const char* data, size_t data_length)
+{
+ my_socket fd= INVALID_SOCKET;
+ char buf[1024];
+ size_t len= 0;
+
+ addrinfo *addrs, *addr, filter= {0, AF_UNSPEC, SOCK_STREAM, 6, 0, 0, 0, 0};
+ int res= use_proxy() ?
+ getaddrinfo(proxy_host.str, proxy_port.str, &filter, &addrs) :
+ getaddrinfo(host.str, port.str, &filter, &addrs);
+
+ if (res)
+ {
+ sql_print_error("feedback plugin: getaddrinfo() failed for url '%s': %s",
+ full_url.str, gai_strerror(res));
+ return 1;
+ }
+
+ for (addr= addrs; addr != NULL; addr= addr->ai_next)
+ {
+ fd= socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
+ if (fd == INVALID_SOCKET)
+ continue;
+
+ if (connect(fd, addr->ai_addr, (int) addr->ai_addrlen) == 0)
+ break;
+
+ closesocket(fd);
+ fd= INVALID_SOCKET;
+ }
+
+ freeaddrinfo(addrs);
+
+ if (fd == INVALID_SOCKET)
+ {
+ sql_print_error("feedback plugin: could not connect for url '%s'",
+ full_url.str);
+ return 1;
+ }
+
+ Vio *vio= vio_new(fd, VIO_TYPE_TCPIP, 0);
+ if (!vio)
+ {
+ sql_print_error("feedback plugin: vio_new failed for url '%s'",
+ full_url.str);
+ closesocket(fd);
+ return 1;
+ }
+
+#ifdef HAVE_OPENSSL
+ struct st_VioSSLFd *UNINIT_VAR(ssl_fd);
+ if (ssl)
+ {
+ enum enum_ssl_init_error ssl_init_error= SSL_INITERR_NOERROR;
+ ulong ssl_error= 0;
+ if (!(ssl_fd= new_VioSSLConnectorFd(0, 0, 0, 0, 0, &ssl_init_error, 0, 0)) ||
+ sslconnect(ssl_fd, vio, send_timeout, &ssl_error))
+ {
+ const char *err;
+ if (ssl_init_error != SSL_INITERR_NOERROR)
+ err= sslGetErrString(ssl_init_error);
+ else
+ {
+ ERR_error_string_n(ssl_error, buf, sizeof(buf));
+ buf[sizeof(buf)-1]= 0;
+ err= buf;
+ }
+
+ sql_print_error("feedback plugin: ssl failed for url '%s' %s",
+ full_url.str, err);
+ if (ssl_fd)
+ free_vio_ssl_acceptor_fd(ssl_fd);
+ closesocket(fd);
+ vio_delete(vio);
+ return 1;
+ }
+ }
+#endif
+
+ static const LEX_STRING boundary=
+ { C_STRING_WITH_LEN("----------------------------ba4f3696b39f") };
+ static const LEX_STRING header=
+ { C_STRING_WITH_LEN("\r\n"
+ "Content-Disposition: form-data; name=\"data\"; filename=\"-\"\r\n"
+ "Content-Type: application/octet-stream\r\n\r\n")
+ };
+
+ len= my_snprintf(buf, sizeof(buf),
+ use_proxy() ? "POST http://%s:%s/" : "POST ",
+ host.str, port.str);
+
+ len+= my_snprintf(buf+len, sizeof(buf)-len,
+ "%s HTTP/1.0\r\n"
+ "User-Agent: MariaDB User Feedback Plugin\r\n"
+ "Host: %s:%s\r\n"
+ "Accept: */*\r\n"
+ "Content-Length: %u\r\n"
+ "Content-Type: multipart/form-data; boundary=%s\r\n"
+ "\r\n",
+ path.str, host.str, port.str,
+ (uint)(2*boundary.length + header.length + data_length + 4),
+ boundary.str + 2);
+
+ vio_timeout(vio, FOR_READING, send_timeout);
+ vio_timeout(vio, FOR_WRITING, send_timeout);
+ res = write_check(vio, buf, len)
+ || write_check(vio, boundary.str, boundary.length)
+ || write_check(vio, header.str, header.length)
+ || write_check(vio, data, data_length)
+ || write_check(vio, boundary.str, boundary.length)
+ || write_check(vio, "--\r\n", 4);
+
+ if (res)
+ sql_print_error("feedback plugin: failed to send report to '%s'",
+ full_url.str);
+ else
+ {
+ sql_print_information("feedback plugin: report to '%s' was sent",
+ full_url.str);
+
+ /*
+ if the data were send successfully, read the reply.
+ Extract the first string between <h1>...</h1> tags
+ and put it as a server reply into the error log.
+ */
+ len= 0;
+ for (;;)
+ {
+ size_t i= sizeof(buf) - len - 1;
+ if (i)
+ i= vio_read(vio, (uchar*)buf + len, i);
+ if ((int)i <= 0)
+ break;
+ len+= i;
+ }
+ if (len)
+ {
+ char *from;
+
+ buf[len]= 0; // safety
+
+ if ((from= strstr(buf, "<h1>")))
+ {
+ from+= 4;
+ char *to= strstr(from, "</h1>");
+ if (to)
+ *to= 0;
+ else
+ from= NULL;
+ }
+ if (from)
+ sql_print_information("feedback plugin: server replied '%s'", from);
+ else
+ sql_print_warning("feedback plugin: failed to parse server reply");
+ }
+ else
+ {
+ res= 1;
+ sql_print_error("feedback plugin: failed to read server reply");
+ }
+ }
+
+ vio_delete(vio);
+
+#ifdef HAVE_OPENSSL
+ if (ssl)
+ {
+ SSL_CTX_free(ssl_fd->ssl_context);
+ my_free(ssl_fd);
+ }
+#endif
+
+ return res;
+}
+
+} // namespace feedback
+
diff --git a/plugin/feedback/utils.cc b/plugin/feedback/utils.cc
new file mode 100644
index 00000000..e3624462
--- /dev/null
+++ b/plugin/feedback/utils.cc
@@ -0,0 +1,442 @@
+/* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "feedback.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if defined (_WIN32)
+#define HAVE_SYS_UTSNAME_H
+
+#ifndef VER_SUITE_WH_SERVER
+#define VER_SUITE_WH_SERVER 0x00008000
+#endif
+
+struct utsname {
+ char sysname[16]; // Name of this implementation of the operating system.
+ char nodename[16]; // Name of this node within the communications
+ // network to which this node is attached, if any.
+ char release[16]; // Current release level of this implementation.
+ char version[256]; // Current version level of this release.
+ char machine[16]; // Name of the hardware type on which the system is running.
+};
+
+/* Get commonly used name for Windows version */
+static const char *get_os_version_name(OSVERSIONINFOEX *ver)
+{
+ DWORD major = ver->dwMajorVersion;
+ DWORD minor = ver->dwMinorVersion;
+ if (major == 10 && minor == 0)
+ {
+ return (ver->wProductType == VER_NT_WORKSTATION) ?
+ "Windows 10" : "Windows Server 2016";
+ }
+ if (major == 6 && minor == 3)
+ {
+ return (ver->wProductType == VER_NT_WORKSTATION)?
+ "Windows 8.1":"Windows Server 2012 R2";
+ }
+ if (major == 6 && minor == 2)
+ {
+ return (ver->wProductType == VER_NT_WORKSTATION)?
+ "Windows 8":"Windows Server 2012";
+ }
+ if (major == 6 && minor == 1)
+ {
+ return (ver->wProductType == VER_NT_WORKSTATION)?
+ "Windows 7":"Windows Server 2008 R2";
+ }
+ if (major == 6 && minor == 0)
+ {
+ return (ver->wProductType == VER_NT_WORKSTATION)?
+ "Windows Vista":"Windows Server 2008";
+ }
+ if (major == 5 && minor == 2)
+ {
+ if (GetSystemMetrics(SM_SERVERR2) != 0)
+ return "Windows Server 2003 R2";
+ if (ver->wSuiteMask & VER_SUITE_WH_SERVER)
+ return "Windows Home Server";
+ SYSTEM_INFO sysinfo;
+ GetSystemInfo(&sysinfo);
+ if (ver->wProductType == VER_NT_WORKSTATION &&
+ sysinfo.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64)
+ return "Windows XP Professional x64 Edition";
+
+ return "Windows Server 2003";
+ }
+ if (major == 5 && minor == 1)
+ return "Windows XP";
+ if (major == 5 && minor == 0)
+ return "Windows 2000";
+
+ return "";
+}
+
+
+static int uname(struct utsname *buf)
+{
+ OSVERSIONINFOEX ver;
+ ver.dwOSVersionInfoSize = (DWORD)sizeof(ver);
+ /* GetVersionEx got deprecated, we need it anyway, so disable deprecation warnings. */
+#ifdef _MSC_VER
+#pragma warning (disable : 4996)
+#endif
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#endif
+ if (!GetVersionEx((OSVERSIONINFO *)&ver))
+ return -1;
+
+ buf->nodename[0]= 0;
+ strcpy(buf->sysname, "Windows");
+ sprintf(buf->release, "%d.%d", (int)ver.dwMajorVersion, (int)ver.dwMinorVersion);
+
+ const char *version_str= get_os_version_name(&ver);
+ if(version_str && version_str[0])
+ sprintf(buf->version, "%s %s",version_str, ver.szCSDVersion);
+ else
+ {
+ /* Fallback for unknown versions, e.g "Windows <major_ver>.<minor_ver>" */
+ sprintf(buf->version, "Windows %d.%d%s",
+ (int)ver.dwMajorVersion, (int)ver.dwMinorVersion,
+ (ver.wProductType == VER_NT_WORKSTATION ? "" : " Server"));
+ }
+
+#ifdef _WIN64
+ strcpy(buf->machine, "x64");
+#else
+ BOOL isX64;
+ if (IsWow64Process(GetCurrentProcess(), &isX64) && isX64)
+ strcpy(buf->machine, "x64");
+ else
+ strcpy(buf->machine,"x86");
+#endif
+ return 0;
+}
+
+#elif defined(HAVE_SYS_UTSNAME_H)
+#include <sys/utsname.h>
+#endif
+
+#ifdef HAVE_SYS_UTSNAME_H
+static bool have_ubuf= false;
+static struct utsname ubuf;
+#endif
+
+#ifdef TARGET_OS_LINUX
+#include <glob.h>
+static bool have_distribution= false;
+static char distribution[256];
+
+static const char *masks[]= {
+ "/etc/*-version", "/etc/*-release",
+ "/etc/*_version", "/etc/*_release"
+};
+#endif
+
+bool schema_table_store_record(THD *thd, TABLE *table);
+
+namespace feedback {
+
+/*
+ convenience macros for inserting rows into I_S table.
+*/
+#define INSERT2(NAME,LEN,VALUE) \
+ do { \
+ table->field[0]->store(NAME, (uint) LEN, system_charset_info); \
+ table->field[1]->store VALUE; \
+ if (schema_table_store_record(thd, table)) \
+ return 1; \
+ } while (0)
+
+#define INSERT1(NAME,VALUE) \
+ do { \
+ table->field[0]->store(NAME, (uint) sizeof(NAME)-1, system_charset_info); \
+ table->field[1]->store VALUE; \
+ if (schema_table_store_record(thd, table)) \
+ return 1; \
+ } while (0)
+
+static const bool UNSIGNED= true; ///< used below when inserting integers
+
+/**
+ callback for fill_plugins()
+*/
+static my_bool show_plugins(THD *thd, plugin_ref plugin, void *arg)
+{
+ TABLE *table= (TABLE*) arg;
+ char name[NAME_LEN*2];
+ size_t name_len;
+ char version[20];
+ size_t version_len;
+
+ name_len= my_snprintf(name, sizeof(name), "%s version",
+ plugin_name(plugin)->str);
+
+ version_len= my_snprintf(version, sizeof(version), "%d.%d",
+ (plugin_decl(plugin)->version) >> 8,
+ (plugin_decl(plugin)->version) & 0xff);
+
+ INSERT2(name, name_len,
+ (version, (uint)version_len, system_charset_info));
+
+ name_len= my_snprintf(name, sizeof(name), "%s used",
+ plugin_name(plugin)->str);
+
+ INSERT2(name, name_len, (plugin_ref_to_int(plugin)->locks_total, UNSIGNED));
+
+ return 0;
+}
+
+/**
+ inserts all plugins, their versions, and usage counters
+*/
+int fill_plugin_version(THD *thd, TABLE_LIST *tables)
+{
+ return plugin_foreach_with_mask(thd, show_plugins, MYSQL_ANY_PLUGIN,
+ ~PLUGIN_IS_FREED, tables->table);
+}
+
+#if defined(_SC_PAGE_SIZE) && !defined(_SC_PAGESIZE)
+#define _SC_PAGESIZE _SC_PAGE_SIZE
+#endif
+
+/**
+ return the amount of physical memory
+*/
+static ulonglong my_getphysmem()
+{
+#ifdef _WIN32
+ MEMORYSTATUSEX memstatus;
+ memstatus.dwLength= sizeof(memstatus);
+ GlobalMemoryStatusEx(&memstatus);
+ return memstatus.ullTotalPhys;
+#else
+ ulonglong pages= 0;
+
+#ifdef _SC_PHYS_PAGES
+ pages= sysconf(_SC_PHYS_PAGES);
+#endif
+
+#ifdef _SC_PAGESIZE
+ return pages * sysconf(_SC_PAGESIZE);
+#else
+ return pages * my_getpagesize();
+#endif
+#endif
+}
+
+/* get the number of (online) CPUs */
+int my_getncpus()
+{
+#ifdef _SC_NPROCESSORS_ONLN
+ return sysconf(_SC_NPROCESSORS_ONLN);
+#elif defined(__WIN__)
+ SYSTEM_INFO sysinfo;
+ GetSystemInfo(&sysinfo);
+ return sysinfo.dwNumberOfProcessors;
+#else
+ return 0;
+#endif
+}
+
+/**
+ Find the version of the kernel and the linux distribution
+*/
+int prepare_linux_info()
+{
+#ifdef HAVE_SYS_UTSNAME_H
+ have_ubuf= (uname(&ubuf) != -1);
+#endif
+
+#ifdef TARGET_OS_LINUX
+ /*
+ let's try to find what linux distribution it is
+ we read *[-_]{release,version} file in /etc.
+
+ Either it will be /etc/lsb-release, such as
+
+ ==> /etc/lsb-release <==
+ DISTRIB_ID=Ubuntu
+ DISTRIB_RELEASE=8.04
+ DISTRIB_CODENAME=hardy
+ DISTRIB_DESCRIPTION="Ubuntu 8.04.4 LTS"
+
+ Or a one-liner with the description (/etc/SuSE-release has more
+ than one line, but the description is the first, so it can be
+ treated as a one-liner).
+
+ We'll read lsb-release first, and if it's not found will search
+ for other files (*-version *-release *_version *_release)
+*/
+ int fd;
+ have_distribution= false;
+ if ((fd= my_open("/etc/lsb-release", O_RDONLY, MYF(0))) != -1)
+ {
+ /* Cool, LSB-compliant distribution! */
+ size_t len= my_read(fd, (uchar*)distribution, sizeof(distribution)-1, MYF(0));
+ my_close(fd, MYF(0));
+ if (len != (size_t)-1)
+ {
+ distribution[len]= 0; // safety
+ char *found= strstr(distribution, "DISTRIB_DESCRIPTION=");
+ if (found)
+ {
+ have_distribution= true;
+ char *end= strstr(found, "\n");
+ if (end == NULL)
+ end= distribution + len;
+ found+= 20;
+
+ if (*found == '"' && end[-1] == '"')
+ {
+ found++;
+ end--;
+ }
+ *end= 0;
+
+ char *to= strmov(distribution, "lsb: ");
+ memmove(to, found, end - found + 1);
+ }
+ }
+ }
+
+ /* if not an LSB-compliant distribution */
+ for (uint i= 0; !have_distribution && i < array_elements(masks); i++)
+ {
+ glob_t found;
+ if (glob(masks[i], GLOB_NOSORT, NULL, &found) == 0)
+ {
+ int fd;
+ if ((fd= my_open(found.gl_pathv[0], O_RDONLY, MYF(0))) != -1)
+ {
+ /*
+ +5 and -8 below cut the file name part out of the
+ full pathname that corresponds to the mask as above.
+ */
+ char *to= strmov(distribution, found.gl_pathv[0] + 5) - 8;
+ *to++= ':';
+ *to++= ' ';
+
+ size_t to_len= distribution + sizeof(distribution) - 1 - to;
+ size_t len= my_read(fd, (uchar*)to, to_len, MYF(0));
+ my_close(fd, MYF(0));
+ if (len != (size_t)-1)
+ {
+ to[len]= 0; // safety
+ char *end= strstr(to, "\n");
+ if (end)
+ *end= 0;
+ have_distribution= true;
+ }
+ }
+ }
+ globfree(&found);
+ }
+#endif
+ return 0;
+}
+
+/**
+ Add the linux distribution and the kernel version
+*/
+int fill_linux_info(THD *thd, TABLE_LIST *tables)
+{
+#if defined(HAVE_SYS_UTSNAME_H) || defined(TARGET_OS_LINUX)
+ TABLE *table= tables->table;
+ CHARSET_INFO *cs= system_charset_info;
+#endif
+
+#ifdef HAVE_SYS_UTSNAME_H
+ if (have_ubuf)
+ {
+ INSERT1("Uname_sysname", (ubuf.sysname, (uint) strlen(ubuf.sysname), cs));
+ INSERT1("Uname_release", (ubuf.release, (uint) strlen(ubuf.release), cs));
+ INSERT1("Uname_version", (ubuf.version, (uint) strlen(ubuf.version), cs));
+ INSERT1("Uname_machine", (ubuf.machine, (uint) strlen(ubuf.machine), cs));
+ }
+#endif
+
+#ifdef TARGET_OS_LINUX
+ if (have_distribution)
+ INSERT1("Uname_distribution", (distribution, strlen(distribution), cs));
+#endif
+
+ return 0;
+}
+
+/**
+ Adds varios bits of information to the I_S.FEEDBACK
+*/
+int fill_misc_data(THD *thd, TABLE_LIST *tables)
+{
+ TABLE *table= tables->table;
+
+ INSERT1("Cpu_count", (my_getncpus(), UNSIGNED));
+ INSERT1("Mem_total", (my_getphysmem(), UNSIGNED));
+ INSERT1("Now", (thd->query_start(), UNSIGNED));
+
+ return 0;
+}
+
+int fill_collation_statistics(THD *thd, TABLE_LIST *tables)
+{
+ TABLE *table= tables->table;
+ for (uint id= 1; id < MY_ALL_CHARSETS_SIZE; id++)
+ {
+ ulonglong count;
+ if (my_collation_is_known_id(id) &&
+ (count= my_collation_statistics_get_use_count(id)))
+ {
+ char name[MY_CS_NAME_SIZE + 32];
+ size_t namelen= my_snprintf(name, sizeof(name),
+ "Collation used %s",
+ get_charset_name(id));
+ INSERT2(name, namelen, (count, UNSIGNED));
+ }
+ }
+ return 0;
+};
+
+/**
+ calculates the server unique identifier
+
+ UID is a base64 encoded SHA1 hash of the MAC address of one of
+ the interfaces, and the tcp port that the server is listening on
+*/
+int calculate_server_uid(char *dest)
+{
+ uchar rawbuf[2 + 6];
+ uchar shabuf[MY_SHA1_HASH_SIZE];
+
+ int2store(rawbuf, mysqld_port);
+ if (my_gethwaddr(rawbuf + 2))
+ {
+ sql_print_error("feedback plugin: failed to retrieve the MAC address");
+ return 1;
+ }
+
+ my_sha1((uint8*) shabuf, (char*) rawbuf, sizeof(rawbuf));
+
+ assert(my_base64_needed_encoded_length(sizeof(shabuf)) <= SERVER_UID_SIZE);
+ my_base64_encode(shabuf, sizeof(shabuf), dest);
+
+ return 0;
+}
+
+} // namespace feedback
diff --git a/plugin/file_key_management/CMakeLists.txt b/plugin/file_key_management/CMakeLists.txt
new file mode 100644
index 00000000..c2f13fb9
--- /dev/null
+++ b/plugin/file_key_management/CMakeLists.txt
@@ -0,0 +1,4 @@
+SET(FILE_KEY_MANAGEMENT_PLUGIN_SOURCES file_key_management_plugin.cc parser.cc)
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql)
+MYSQL_ADD_PLUGIN(FILE_KEY_MANAGEMENT ${FILE_KEY_MANAGEMENT_PLUGIN_SOURCES})
diff --git a/plugin/file_key_management/file_key_management_plugin.cc b/plugin/file_key_management/file_key_management_plugin.cc
new file mode 100644
index 00000000..927045ce
--- /dev/null
+++ b/plugin/file_key_management/file_key_management_plugin.cc
@@ -0,0 +1,207 @@
+/* Copyright (c) 2002, 2012, eperi GmbH.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include <my_global.h>
+#include <typelib.h>
+#include "parser.h"
+#include <mysql/plugin_encryption.h>
+#include <string.h>
+
+static char* filename;
+static char* filekey;
+static unsigned long encryption_algorithm;
+
+static const char *encryption_algorithm_names[]=
+{
+ "aes_cbc",
+#ifdef HAVE_EncryptAes128Ctr
+ "aes_ctr",
+#endif
+ 0
+};
+
+static TYPELIB encryption_algorithm_typelib=
+{
+ array_elements(encryption_algorithm_names)-1,"",
+ encryption_algorithm_names, NULL
+};
+
+
+static MYSQL_SYSVAR_STR(filename, filename,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "Path and name of the key file.",
+ NULL, NULL, "");
+
+static MYSQL_SYSVAR_STR(filekey, filekey,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "Key to encrypt / decrypt the keyfile.",
+ NULL, NULL, "");
+
+#ifdef HAVE_EncryptAes128Ctr
+#define recommendation ", aes_ctr is the recommended one"
+#else
+#define recommendation ""
+#endif
+static MYSQL_SYSVAR_ENUM(encryption_algorithm, encryption_algorithm,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "Encryption algorithm to use" recommendation ".",
+ NULL, NULL, 0, &encryption_algorithm_typelib);
+
+static struct st_mysql_sys_var* settings[] = {
+ MYSQL_SYSVAR(filename),
+ MYSQL_SYSVAR(filekey),
+ MYSQL_SYSVAR(encryption_algorithm),
+ NULL
+};
+
+std::map<unsigned int,keyentry> keys;
+
+static keyentry *get_key(unsigned int key_id)
+{
+ keyentry &key= keys[key_id];
+ if (key.id == 0)
+ return 0;
+ return &key;
+}
+
+/* the version is always the same, no automatic key rotation */
+static unsigned int get_latest_version(uint key_id)
+{
+ return get_key(key_id) ? 1 : ENCRYPTION_KEY_VERSION_INVALID;
+}
+
+static unsigned int get_key_from_key_file(unsigned int key_id,
+ unsigned int key_version, unsigned char* dstbuf, unsigned *buflen)
+{
+ if (key_version != 1)
+ return ENCRYPTION_KEY_VERSION_INVALID;
+
+ keyentry* entry = get_key(key_id);
+
+ if (entry == NULL)
+ return ENCRYPTION_KEY_VERSION_INVALID;
+
+ if (*buflen < entry->length)
+ {
+ *buflen= entry->length;
+ return ENCRYPTION_KEY_BUFFER_TOO_SMALL;
+ }
+
+ *buflen= entry->length;
+ if (dstbuf)
+ memcpy(dstbuf, entry->key, entry->length);
+
+ return 0;
+}
+
+// let's simplify the condition below
+#ifndef HAVE_EncryptAes128Gcm
+#define MY_AES_GCM MY_AES_CTR
+#ifndef HAVE_EncryptAes128Ctr
+#define MY_AES_CTR MY_AES_CBC
+#endif
+#endif
+
+static inline enum my_aes_mode mode(int flags)
+{
+ /*
+ If encryption_algorithm is AES_CTR then
+ if no-padding, use AES_CTR
+ else use AES_GCM (like CTR but appends a "checksum" block)
+ else
+ use AES_CBC
+ */
+ if (encryption_algorithm)
+ if (flags & ENCRYPTION_FLAG_NOPAD)
+ return MY_AES_CTR;
+ else
+ return MY_AES_GCM;
+ else
+ return MY_AES_CBC;
+}
+
+static int ctx_init(void *ctx, const unsigned char* key, unsigned int klen,
+ const unsigned char* iv, unsigned int ivlen, int flags,
+ unsigned int key_id, unsigned int key_version)
+{
+ return my_aes_crypt_init(ctx, mode(flags), flags, key, klen, iv, ivlen);
+}
+
+static int ctx_update(void *ctx, const unsigned char *src, unsigned int slen,
+ unsigned char *dst, unsigned int *dlen)
+{
+ return my_aes_crypt_update(ctx, src, slen, dst, dlen);
+}
+
+
+static int ctx_finish(void *ctx, unsigned char *dst, unsigned int *dlen)
+{
+ return my_aes_crypt_finish(ctx, dst, dlen);
+}
+
+static unsigned int get_length(unsigned int slen, unsigned int key_id,
+ unsigned int key_version)
+{
+ return my_aes_get_size(mode(0), slen);
+}
+
+static uint ctx_size(uint, uint)
+{
+ return my_aes_ctx_size(mode(0));
+}
+
+struct st_mariadb_encryption file_key_management_plugin= {
+ MariaDB_ENCRYPTION_INTERFACE_VERSION,
+ get_latest_version,
+ get_key_from_key_file,
+ ctx_size,
+ ctx_init,
+ ctx_update,
+ ctx_finish,
+ get_length
+};
+
+static int file_key_management_plugin_init(void *p)
+{
+ Parser parser(filename, filekey);
+ return parser.parse(&keys);
+}
+
+static int file_key_management_plugin_deinit(void *p)
+{
+ keys.clear();
+ return 0;
+}
+
+/*
+ Plugin library descriptor
+*/
+maria_declare_plugin(file_key_management)
+{
+ MariaDB_ENCRYPTION_PLUGIN,
+ &file_key_management_plugin,
+ "file_key_management",
+ "Denis Endro eperi GmbH",
+ "File-based key management plugin",
+ PLUGIN_LICENSE_GPL,
+ file_key_management_plugin_init,
+ file_key_management_plugin_deinit,
+ 0x0100 /* 1.0 */,
+ NULL, /* status variables */
+ settings,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
diff --git a/plugin/file_key_management/parser.cc b/plugin/file_key_management/parser.cc
new file mode 100644
index 00000000..818c0264
--- /dev/null
+++ b/plugin/file_key_management/parser.cc
@@ -0,0 +1,402 @@
+/* Copyright (C) 2014 eperi GmbH.
+ Copyright (C) 2015 MariaDB Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/******************************************************************//**
+ @file Parser.cc
+ A class to parse the key file
+
+How it works...
+The location and usage can be configured via the configuration file.
+Example
+
+[mysqld]
+...
+file_key_management_filename = /home/mdb/keys.enc
+file_key_management_filekey = secret
+...
+
+The keys are read from a file.
+The filename is set up via the file_key_management_filename
+configuration value.
+file_key_management_filename is used to configure the absolute
+path to this file.
+
+Examples:
+file_key_management_filename = \\\\unc\\keys.enc (windows share)
+file_key_management_filename = e:/tmp/keys.enc (windows path)
+file_key_management_filename = /tmp/keys.enc (linux path)
+
+The key file contains AES keys as hex-encoded strings.
+Supported are keys of size 128, 192 or 256 bits.
+Example:
+1;F5502320F8429037B8DAEF761B189D12
+2;770A8A65DA156D24EE2A093277530142770A8A65DA156D24EE2A093277530142
+
+1 is the key identifier which can be used for table creation,
+it is followed by a AES key
+
+The key file could be encrypted and the key to decrypt the file can
+be given with the optional file_key_management_filekey
+parameter.
+
+The file key can also be located if FILE: is prepended to the
+key. Then the following part is interpreted as absolute path to the
+file containing the file key (which must be a text - not binary - string).
+
+Example:
+
+file_key_management_filekey = FILE:y:/secret256.enc
+
+If the key file can not be read at server startup, for example if the
+file key is not present, the plugin will not start
+access to encrypted tables will not be possible.
+
+Open SSL command line utility can be used to create an encrypted key file.
+Example:
+openssl enc -aes-256-cbc -md sha1 -k "secret" -in keys.txt -out keys.enc
+***********************************************************************/
+
+#include <my_global.h>
+#include "parser.h"
+#include <m_string.h>
+#include <mysys_err.h>
+
+#define FILE_PREFIX "FILE:"
+#define MAX_KEY_FILE_SIZE 1024*1024
+#define MAX_SECRET_SIZE 256
+
+/*
+ The values below are what one gets after
+ openssl enc -aes-256-cbc -md sha1 -k "secret" -in keys.txt -out keys.enc
+*/
+#define OpenSSL_prefix "Salted__"
+#define OpenSSL_prefix_len (sizeof(OpenSSL_prefix) - 1)
+#define OpenSSL_salt_len 8
+#define OpenSSL_key_len 32
+#define OpenSSL_iv_len 16
+
+/**
+ Calculate key and iv from a given salt and secret as in the
+ openssl command-line tool
+
+ @param salt [in] the given salt as extracted from the encrypted file
+ @param secret [in] the given secret as String, provided by the user
+ @param key [out] 32 Bytes of key are written to this pointer
+ @param iv [out] 16 Bytes of iv are written to this pointer
+*/
+
+void Parser::bytes_to_key(const unsigned char *salt, const char *input,
+ unsigned char *key, unsigned char *iv)
+{
+ unsigned char digest[MY_SHA1_HASH_SIZE];
+ int key_left = OpenSSL_key_len;
+ int iv_left = OpenSSL_iv_len;
+ const size_t ilen= strlen(input);
+ const size_t slen= OpenSSL_salt_len; // either this or explicit (size_t) casts below
+
+ my_sha1_multi(digest, input, ilen, salt, slen, NullS);
+
+ while (iv_left)
+ {
+ int left= MY_SHA1_HASH_SIZE;
+ if (key_left)
+ {
+ int store = MY_MIN(key_left, MY_SHA1_HASH_SIZE);
+ memcpy(&key[OpenSSL_key_len - key_left], digest, store);
+
+ key_left -= store;
+ left -= store;
+ }
+
+ if (iv_left && left)
+ {
+ int store= MY_MIN(iv_left, left);
+ memcpy(&iv[OpenSSL_iv_len - iv_left], &digest[MY_SHA1_HASH_SIZE - left], store);
+
+ iv_left -= store;
+ }
+
+ if (iv_left)
+ my_sha1_multi(digest, digest, MY_SHA1_HASH_SIZE,
+ input, ilen, salt, slen, NullS);
+ }
+}
+
+
+bool Parser::parse(std::map<uint,keyentry> *keys)
+{
+ const char *secret= filekey;
+ char buf[MAX_SECRET_SIZE + 1];
+
+ //If secret starts with FILE: interpret the secret as a filename.
+ if (strncmp(filekey, FILE_PREFIX,sizeof(FILE_PREFIX) -1) == 0)
+ {
+ if (read_filekey(filekey + sizeof(FILE_PREFIX) - 1, buf))
+ return 1;
+ secret= buf;
+ }
+
+ return parse_file(keys, secret);
+}
+
+
+/*
+ secret is limited to MAX_SECRET_SIZE characters
+*/
+
+bool Parser::read_filekey(const char *filekey, char *secret)
+{
+ int f= open(filekey, O_RDONLY|O_BINARY);
+ if (f == -1)
+ {
+ my_error(EE_FILENOTFOUND,ME_ERROR_LOG, filekey, errno);
+ return 1;
+ }
+
+ int len= read(f, secret, MAX_SECRET_SIZE);
+ if (len <= 0)
+ {
+ my_error(EE_READ,ME_ERROR_LOG, filekey, errno);
+ close(f);
+ return 1;
+ }
+ close(f);
+ while (secret[len - 1] == '\r' || secret[len - 1] == '\n') len--;
+ secret[len]= '\0';
+ return 0;
+}
+
+
+/**
+ Get the keys from the key file <filename> and decrypt it with the
+ key <secret>. Store the keys with id smaller then <maxKeyId> in an
+ array of structs keyentry.
+
+ @return 0 when ok, 1 for an error
+ */
+
+bool Parser::parse_file(std::map<uint,keyentry> *keys, const char *secret)
+{
+ char *buffer= read_and_decrypt_file(secret);
+
+ if (!buffer)
+ return 1;
+
+ keyentry key;
+ char *line=buffer;
+
+ while (*line)
+ {
+ line_number++;
+ switch (parse_line(&line, &key)) {
+ case 1: // comment
+ break;
+ case -1: // error
+ free(buffer);
+ return 1;
+ case 0:
+ (*keys)[key.id] = key;
+ break;
+ }
+ }
+
+ free(buffer);
+ if (keys->size() == 0 || (*keys)[1].id == 0)
+ {
+ report_error("System key id 1 is missing", 0);
+ return 1;
+ }
+
+ return 0;
+}
+
+void Parser::report_error(const char *reason, size_t position)
+{
+ my_printf_error(EE_READ, "%s at %s line %u, column %zu",
+ ME_ERROR_LOG, reason, filename, line_number, position + 1);
+}
+
+/*
+ return 0 - new key
+ 1 - comment
+ -1 - error
+*/
+int Parser::parse_line(char **line_ptr, keyentry *key)
+{
+ int res= 1;
+ char *p= *line_ptr;
+ while (isspace(*p) && *p != '\n') p++;
+ if (*p != '#' && *p != '\n')
+ {
+ if (!isdigit(*p))
+ {
+ report_error("Syntax error", p - *line_ptr);
+ return -1;
+ }
+
+ longlong id = 0;
+ while (isdigit(*p))
+ {
+ id = id * 10 + *p - '0';
+ if (id > UINT_MAX32)
+ {
+ report_error("Invalid key id", p - *line_ptr);
+ return -1;
+ }
+ p++;
+ }
+
+ if (id < 1)
+ {
+ report_error("Invalid key id", p - *line_ptr);
+ return -1;
+ }
+
+ if (*p != ';')
+ {
+ report_error("Syntax error", p - *line_ptr);
+ return -1;
+ }
+
+ p++;
+ key->id= (unsigned int)id;
+ key->length=0;
+ while (isxdigit(p[0]) && isxdigit(p[1]) && key->length < sizeof(key->key))
+ {
+ key->key[key->length++] = from_hex(p[0]) * 16 + from_hex(p[1]);
+ p+=2;
+ }
+ if (isxdigit(*p) ||
+ (key->length != 16 && key->length != 24 && key->length != 32))
+ {
+ report_error("Invalid key", p - *line_ptr);
+ return -1;
+ }
+
+ res= 0;
+ }
+ while (*p && *p != '\n') p++;
+ *line_ptr= *p == '\n' ? p + 1 : p;
+ return res;
+}
+
+/**
+ Decrypt the key file 'filename' if it is encrypted with the key
+ 'secret'. Store the content of the decrypted file in 'buffer'. The
+ buffer has to be freed in the calling function.
+ */
+#ifdef _WIN32
+#define lseek _lseeki64
+#endif
+
+char* Parser::read_and_decrypt_file(const char *secret)
+{
+ int f;
+ if (!filename || !filename[0])
+ {
+ my_printf_error(EE_CANT_OPEN_STREAM, "file-key-management-filename is not set",
+ ME_ERROR_LOG);
+ goto err0;
+ }
+
+ f= open(filename, O_RDONLY|O_BINARY, 0);
+ if (f < 0)
+ {
+ my_error(EE_FILENOTFOUND, ME_ERROR_LOG, filename, errno);
+ goto err0;
+ }
+
+ my_off_t file_size;
+ file_size= lseek(f, 0, SEEK_END);
+
+ if (file_size == MY_FILEPOS_ERROR || (my_off_t)lseek(f, 0, SEEK_SET) == MY_FILEPOS_ERROR)
+ {
+ my_error(EE_CANT_SEEK, MYF(0), filename, errno);
+ goto err1;
+ }
+
+ if (file_size > MAX_KEY_FILE_SIZE)
+ {
+ my_error(EE_READ, MYF(0), filename, EFBIG);
+ goto err1;
+ }
+
+ //Read file into buffer
+ uchar *buffer;
+ buffer= (uchar*)malloc((size_t)file_size + 1);
+ if (!buffer)
+ {
+ my_error(EE_OUTOFMEMORY, ME_ERROR_LOG| ME_FATAL, file_size);
+ goto err1;
+ }
+
+ if (read(f, buffer, (int)file_size) != (int)file_size)
+ {
+ my_printf_error(EE_READ,
+ "read from %s failed, errno %d",
+ MYF(ME_ERROR_LOG|ME_FATAL), filename, errno);
+ goto err2;
+ }
+
+// Check for file encryption
+ uchar *decrypted;
+ if (file_size > OpenSSL_prefix_len && strncmp((char*)buffer, OpenSSL_prefix, OpenSSL_prefix_len) == 0)
+ {
+ uchar key[OpenSSL_key_len];
+ uchar iv[OpenSSL_iv_len];
+
+ decrypted= (uchar*)malloc((size_t)file_size);
+ if (!decrypted)
+ {
+ my_error(EE_OUTOFMEMORY, ME_ERROR_LOG | ME_FATAL, file_size);
+ goto err2;
+ }
+ bytes_to_key(buffer + OpenSSL_prefix_len, secret, key, iv);
+ uint32 d_size;
+ if (my_aes_crypt(MY_AES_CBC, ENCRYPTION_FLAG_DECRYPT,
+ buffer + OpenSSL_prefix_len + OpenSSL_salt_len,
+ (unsigned int)file_size - OpenSSL_prefix_len - OpenSSL_salt_len,
+ decrypted, &d_size, key, OpenSSL_key_len,
+ iv, OpenSSL_iv_len))
+
+ {
+ my_printf_error(EE_READ, "Cannot decrypt %s. Wrong key?", ME_ERROR_LOG, filename);
+ goto err3;
+ }
+
+ free(buffer);
+ buffer= decrypted;
+ file_size= d_size;
+ }
+ else if (*secret)
+ {
+ my_printf_error(EE_READ, "Cannot decrypt %s. Not encrypted", ME_ERROR_LOG, filename);
+ goto err2;
+ }
+
+ buffer[file_size]= '\0';
+ close(f);
+ return (char*) buffer;
+
+err3:
+ free(decrypted);
+err2:
+ free(buffer);
+err1:
+ close(f);
+err0:
+ return NULL;
+}
diff --git a/plugin/file_key_management/parser.h b/plugin/file_key_management/parser.h
new file mode 100644
index 00000000..e2fda758
--- /dev/null
+++ b/plugin/file_key_management/parser.h
@@ -0,0 +1,55 @@
+/* Copyright (C) 2014 eperi GmbH.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/******************************************************************//**
+@file Parser.h
+A structure and class to keep keys for encryption/decryption.
+
+Created 09/15/2014
+***********************************************************************/
+
+#include <my_crypt.h>
+#include <ctype.h>
+#include <map>
+#include <stdlib.h> /* size_t */
+
+struct keyentry {
+ unsigned int id;
+ unsigned char key[MY_AES_MAX_KEY_LENGTH];
+ unsigned int length;
+};
+
+class Parser
+{
+ const char *filename;
+ const char *filekey;
+ unsigned int line_number;
+
+ unsigned int from_hex(char c)
+ { return c <= '9' ? c - '0' : tolower(c) - 'a' + 10; }
+
+ void bytes_to_key(const unsigned char *salt, const char *secret,
+ unsigned char *key, unsigned char *iv);
+ bool read_filekey(const char *filekey, char *secret);
+ bool parse_file(std::map<unsigned int ,keyentry> *keys, const char *secret);
+ void report_error(const char *reason, size_t position);
+ int parse_line(char **line_ptr, keyentry *key);
+ char* read_and_decrypt_file(const char *secret);
+
+public:
+ Parser(const char* fn, const char *fk) :
+ filename(fn), filekey(fk), line_number(0) { }
+ bool parse(std::map<unsigned int ,keyentry> *keys);
+};
diff --git a/plugin/fulltext/AUTHORS b/plugin/fulltext/AUTHORS
new file mode 100644
index 00000000..9c456788
--- /dev/null
+++ b/plugin/fulltext/AUTHORS
@@ -0,0 +1 @@
+AUTHORS file example for a plugin
diff --git a/plugin/fulltext/CMakeLists.txt b/plugin/fulltext/CMakeLists.txt
new file mode 100644
index 00000000..23710ee1
--- /dev/null
+++ b/plugin/fulltext/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (c) 2006, 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
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
+
+MYSQL_ADD_PLUGIN(ftexample plugin_example.c
+ MODULE_ONLY MODULE_OUTPUT_NAME "mypluglib" COMPONENT Test)
diff --git a/plugin/fulltext/ChangeLog b/plugin/fulltext/ChangeLog
new file mode 100644
index 00000000..1faaaad6
--- /dev/null
+++ b/plugin/fulltext/ChangeLog
@@ -0,0 +1 @@
+ChangeLog file example for a plugin
diff --git a/plugin/fulltext/NEWS b/plugin/fulltext/NEWS
new file mode 100644
index 00000000..e5b6cbd5
--- /dev/null
+++ b/plugin/fulltext/NEWS
@@ -0,0 +1 @@
+NEWS file example for a plugin
diff --git a/plugin/fulltext/README b/plugin/fulltext/README
new file mode 100644
index 00000000..e4d01f2a
--- /dev/null
+++ b/plugin/fulltext/README
@@ -0,0 +1 @@
+README file example for a plugin
diff --git a/plugin/fulltext/plugin_example.c b/plugin/fulltext/plugin_example.c
new file mode 100644
index 00000000..fb8de478
--- /dev/null
+++ b/plugin/fulltext/plugin_example.c
@@ -0,0 +1,273 @@
+/* Copyright (c) 2005, 2011, Oracle and/or its affiliates
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <mysql/plugin.h>
+
+#if !defined(__attribute__) && (defined(__cplusplus) || !defined(__GNUC__) || __GNUC__ == 2 && __GNUC_MINOR__ < 8)
+#define __attribute__(A)
+#endif
+
+static long number_of_calls= 0; /* for SHOW STATUS, see below */
+
+/*
+ Simple full-text parser plugin that acts as a replacement for the
+ built-in full-text parser:
+ - All non-whitespace characters are significant and are interpreted as
+ "word characters."
+ - Whitespace characters are space, tab, CR, LF.
+ - There is no minimum word length. Non-whitespace sequences of one
+ character or longer are words.
+ - Stopwords are used in non-boolean mode, not used in boolean mode.
+*/
+
+/*
+ simple_parser interface functions:
+
+ Plugin declaration functions:
+ - simple_parser_plugin_init()
+ - simple_parser_plugin_deinit()
+
+ Parser descriptor functions:
+ - simple_parser_parse()
+ - simple_parser_init()
+ - simple_parser_deinit()
+*/
+
+
+/*
+ Initialize the parser plugin at server start or plugin installation.
+
+ SYNOPSIS
+ simple_parser_plugin_init()
+
+ DESCRIPTION
+ Does nothing.
+
+ RETURN VALUE
+ 0 success
+ 1 failure (cannot happen)
+*/
+
+static int simple_parser_plugin_init(void *arg __attribute__((unused)))
+{
+ return(0);
+}
+
+
+/*
+ Terminate the parser plugin at server shutdown or plugin deinstallation.
+
+ SYNOPSIS
+ simple_parser_plugin_deinit()
+ Does nothing.
+
+ RETURN VALUE
+ 0 success
+ 1 failure (cannot happen)
+
+*/
+
+static int simple_parser_plugin_deinit(void *arg __attribute__((unused)))
+{
+ return(0);
+}
+
+
+/*
+ Initialize the parser on the first use in the query
+
+ SYNOPSIS
+ simple_parser_init()
+
+ DESCRIPTION
+ Does nothing.
+
+ RETURN VALUE
+ 0 success
+ 1 failure (cannot happen)
+*/
+
+static int simple_parser_init(MYSQL_FTPARSER_PARAM *param
+ __attribute__((unused)))
+{
+ return(0);
+}
+
+
+/*
+ Terminate the parser at the end of the query
+
+ SYNOPSIS
+ simple_parser_deinit()
+
+ DESCRIPTION
+ Does nothing.
+
+ RETURN VALUE
+ 0 success
+ 1 failure (cannot happen)
+*/
+
+static int simple_parser_deinit(MYSQL_FTPARSER_PARAM *param
+ __attribute__((unused)))
+{
+ return(0);
+}
+
+
+/*
+ Pass a word back to the server.
+
+ SYNOPSIS
+ add_word()
+ param parsing context of the plugin
+ word a word
+ len word length
+
+ DESCRIPTION
+ Fill in boolean metadata for the word (if parsing in boolean mode)
+ and pass the word to the server. The server adds the word to
+ a full-text index when parsing for indexing, or adds the word to
+ the list of search terms when parsing a search string.
+*/
+
+static void add_word(MYSQL_FTPARSER_PARAM *param, const char *word, size_t len)
+{
+ MYSQL_FTPARSER_BOOLEAN_INFO bool_info=
+ { FT_TOKEN_WORD, 0, 0, 0, 0, ' ', 0 };
+
+ param->mysql_add_word(param, word, (int)len, &bool_info);
+}
+
+/*
+ Parse a document or a search query.
+
+ SYNOPSIS
+ simple_parser_parse()
+ param parsing context
+
+ DESCRIPTION
+ This is the main plugin function which is called to parse
+ a document or a search query. The call mode is set in
+ param->mode. This function simply splits the text into words
+ and passes every word to the MySQL full-text indexing engine.
+*/
+
+static int simple_parser_parse(MYSQL_FTPARSER_PARAM *param)
+{
+ const char *end, *start, *docend= param->doc + param->length;
+
+ number_of_calls++;
+
+ for (end= start= param->doc;; end++)
+ {
+ if (end == docend)
+ {
+ if (end > start)
+ add_word(param, start, end - start);
+ break;
+ }
+ else if (isspace(*end))
+ {
+ if (end > start)
+ add_word(param, start, end - start);
+ start= end + 1;
+ }
+ }
+ return(0);
+}
+
+
+/*
+ Plugin type-specific descriptor
+*/
+
+static struct st_mysql_ftparser simple_parser_descriptor=
+{
+ MYSQL_FTPARSER_INTERFACE_VERSION, /* interface version */
+ simple_parser_parse, /* parsing function */
+ simple_parser_init, /* parser init function */
+ simple_parser_deinit /* parser deinit function */
+};
+
+/*
+ Plugin status variables for SHOW STATUS
+*/
+
+static struct st_mysql_show_var simple_status[]=
+{
+ {"A_static", (char *)"just a static text", SHOW_CHAR},
+ {"called", (char *)&number_of_calls, SHOW_LONG},
+ {0,0,0}
+};
+
+/*
+ Plugin system variables.
+*/
+
+static long sysvar_one_value;
+static char *sysvar_two_value;
+
+static MYSQL_SYSVAR_LONG(simple_sysvar_one, sysvar_one_value,
+ PLUGIN_VAR_RQCMDARG,
+ "Simple fulltext parser example system variable number one. Give a number.",
+ NULL, NULL, 77L, 7L, 777L, 0);
+
+static MYSQL_SYSVAR_STR(simple_sysvar_two, sysvar_two_value,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
+ "Simple fulltext parser example system variable number two. Give a string.",
+ NULL, NULL, "simple sysvar two default");
+
+static MYSQL_THDVAR_LONG(simple_thdvar_one,
+ PLUGIN_VAR_RQCMDARG,
+ "Simple fulltext parser example thread variable number one. Give a number.",
+ NULL, NULL, 88L, 8L, 888L, 0);
+
+static MYSQL_THDVAR_STR(simple_thdvar_two,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
+ "Simple fulltext parser example thread variable number two. Give a string.",
+ NULL, NULL, "simple thdvar two default");
+
+static struct st_mysql_sys_var* simple_system_variables[]= {
+ MYSQL_SYSVAR(simple_sysvar_one),
+ MYSQL_SYSVAR(simple_sysvar_two),
+ MYSQL_SYSVAR(simple_thdvar_one),
+ MYSQL_SYSVAR(simple_thdvar_two),
+ NULL
+};
+
+/*
+ Plugin library descriptor
+*/
+
+maria_declare_plugin(ftexample)
+{
+ MYSQL_FTPARSER_PLUGIN, /* type */
+ &simple_parser_descriptor, /* descriptor */
+ "simple_parser", /* name */
+ "Sergei Golubchik", /* author */
+ "Simple Full-Text Parser", /* description */
+ PLUGIN_LICENSE_GPL,
+ simple_parser_plugin_init, /* init function (when loaded) */
+ simple_parser_plugin_deinit,/* deinit function (when unloaded) */
+ 0x0001, /* version */
+ simple_status, /* status variables */
+ simple_system_variables, /* system variables */
+ "0.01", /* string version */
+ MariaDB_PLUGIN_MATURITY_EXPERIMENTAL /* maturity */
+}
+maria_declare_plugin_end;
diff --git a/plugin/func_test/CMakeLists.txt b/plugin/func_test/CMakeLists.txt
new file mode 100644
index 00000000..38ce82d3
--- /dev/null
+++ b/plugin/func_test/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (c) 2019, MariaDB corporation. 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
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+MYSQL_ADD_PLUGIN(func_test plugin.cc RECOMPILE_FOR_EMBEDDED
+ MODULE_ONLY COMPONENT Test)
diff --git a/plugin/func_test/mysql-test/func_test/func_test.result b/plugin/func_test/mysql-test/func_test/func_test.result
new file mode 100644
index 00000000..92d03fbd
--- /dev/null
+++ b/plugin/func_test/mysql-test/func_test/func_test.result
@@ -0,0 +1,28 @@
+SELECT
+PLUGIN_NAME,
+PLUGIN_VERSION,
+PLUGIN_STATUS,
+PLUGIN_TYPE,
+PLUGIN_AUTHOR,
+PLUGIN_DESCRIPTION,
+PLUGIN_LICENSE,
+PLUGIN_MATURITY,
+PLUGIN_AUTH_VERSION
+FROM INFORMATION_SCHEMA.PLUGINS
+WHERE PLUGIN_TYPE='FUNCTION'
+ AND PLUGIN_NAME='sysconst_test';
+PLUGIN_NAME sysconst_test
+PLUGIN_VERSION 1.0
+PLUGIN_STATUS ACTIVE
+PLUGIN_TYPE FUNCTION
+PLUGIN_AUTHOR MariaDB Corporation
+PLUGIN_DESCRIPTION Function SYSCONST_TEST()
+PLUGIN_LICENSE GPL
+PLUGIN_MATURITY Experimental
+PLUGIN_AUTH_VERSION 1.0
+SELECT sysconst_test();
+sysconst_test()
+sysconst_test
+SELECT sysconst_test();
+sysconst_test()
+sysconst_test
diff --git a/plugin/func_test/mysql-test/func_test/func_test.test b/plugin/func_test/mysql-test/func_test/func_test.test
new file mode 100644
index 00000000..d5e6a604
--- /dev/null
+++ b/plugin/func_test/mysql-test/func_test/func_test.test
@@ -0,0 +1,23 @@
+#--echo #
+#--echo #
+#--echo #
+
+--vertical_results
+SELECT
+ PLUGIN_NAME,
+ PLUGIN_VERSION,
+ PLUGIN_STATUS,
+ PLUGIN_TYPE,
+ PLUGIN_AUTHOR,
+ PLUGIN_DESCRIPTION,
+ PLUGIN_LICENSE,
+ PLUGIN_MATURITY,
+ PLUGIN_AUTH_VERSION
+FROM INFORMATION_SCHEMA.PLUGINS
+WHERE PLUGIN_TYPE='FUNCTION'
+ AND PLUGIN_NAME='sysconst_test';
+--horizontal_results
+
+
+SELECT sysconst_test();
+SELECT sysconst_test();
diff --git a/plugin/func_test/mysql-test/func_test/suite.opt b/plugin/func_test/mysql-test/func_test/suite.opt
new file mode 100644
index 00000000..8c8bfe0f
--- /dev/null
+++ b/plugin/func_test/mysql-test/func_test/suite.opt
@@ -0,0 +1 @@
+--plugin-load-add=$FUNC_TEST_SO
diff --git a/plugin/func_test/mysql-test/func_test/suite.pm b/plugin/func_test/mysql-test/func_test/suite.pm
new file mode 100644
index 00000000..ddaa6b55
--- /dev/null
+++ b/plugin/func_test/mysql-test/func_test/suite.pm
@@ -0,0 +1,9 @@
+package My::Suite::Func_test;
+
+@ISA = qw(My::Suite);
+
+return "No FUNC_TEST plugin" unless $ENV{FUNC_TEST_SO};
+
+sub is_default { 1 }
+
+bless { };
diff --git a/plugin/func_test/plugin.cc b/plugin/func_test/plugin.cc
new file mode 100644
index 00000000..81118977
--- /dev/null
+++ b/plugin/func_test/plugin.cc
@@ -0,0 +1,87 @@
+/*
+ Copyright (c) 2019, MariaDB Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#define MYSQL_SERVER
+
+#include <my_global.h>
+#include <sql_class.h>
+#include <mysql/plugin_function.h>
+
+class Item_func_sysconst_test :public Item_func_sysconst
+{
+public:
+ Item_func_sysconst_test(THD *thd): Item_func_sysconst(thd) {}
+ String *val_str(String *str)
+ {
+ null_value= str->copy(STRING_WITH_LEN("sysconst_test"), system_charset_info);
+ return null_value ? NULL : str;
+ }
+ bool fix_length_and_dec()
+ {
+ max_length= MAX_FIELD_NAME * system_charset_info->mbmaxlen;
+ maybe_null= true;
+ return false;
+ }
+ const char *func_name() const { return "sysconst_test"; }
+ const char *fully_qualified_func_name() const { return "sysconst_test()"; }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_sysconst_test>(thd, this); }
+};
+
+
+class Create_func_sysconst_test : public Create_func_arg0
+{
+public:
+ Item *create_builder(THD *thd) override;
+ static Create_func_sysconst_test s_singleton;
+protected:
+ Create_func_sysconst_test() {}
+};
+
+
+Create_func_sysconst_test Create_func_sysconst_test::s_singleton;
+
+Item* Create_func_sysconst_test::create_builder(THD *thd)
+{
+ return new (thd->mem_root) Item_func_sysconst_test(thd);
+}
+
+
+#define BUILDER(F) & F::s_singleton
+
+
+static Plugin_function
+ plugin_descriptor_function_sysconst_test(BUILDER(Create_func_sysconst_test));
+
+/*************************************************************************/
+
+maria_declare_plugin(type_test)
+{
+ MariaDB_FUNCTION_PLUGIN, // the plugin type (see include/mysql/plugin.h)
+ &plugin_descriptor_function_sysconst_test, // pointer to type-specific plugin descriptor
+ "sysconst_test", // plugin name
+ "MariaDB Corporation", // plugin author
+ "Function SYSCONST_TEST()", // the plugin description
+ PLUGIN_LICENSE_GPL, // the plugin license (see include/mysql/plugin.h)
+ 0, // Pointer to plugin initialization function
+ 0, // Pointer to plugin deinitialization function
+ 0x0100, // Numeric version 0xAABB means AA.BB version
+ NULL, // Status variables
+ NULL, // System variables
+ "1.0", // String version representation
+ MariaDB_PLUGIN_MATURITY_EXPERIMENTAL // Maturity(see include/mysql/plugin.h)*/
+}
+maria_declare_plugin_end;
diff --git a/plugin/handler_socket/AUTHORS b/plugin/handler_socket/AUTHORS
new file mode 100644
index 00000000..b60fb015
--- /dev/null
+++ b/plugin/handler_socket/AUTHORS
@@ -0,0 +1,22 @@
+Akira Higuchi (https://github.com/ahiguti)
+ - developed HanderSocket plugin, libhsclient, and perl-Net-HandlerSocket
+
+Yoshinori Matsunobu (https://github.com/yoshinorim)
+ - introduced autotools, added support for MySQL 5.5.6, added statistics
+ variables
+
+Jeff Hodges (https://github.com/jmhodges)
+ - fixed some autotools scripts
+
+Toru Yamaguchi (https://github.com/zigorou)
+ - ported to MacOS X
+
+Moriyoshi Koizumi (https://github.com/moriyoshi)
+ - fixed some autotools scripts
+
+takeda-at (https://github.com/takada-at)
+ - added simple authorization function
+
+WheresWardy (https://github.com/WheresWardy)
+ - added authentication functions to libhsclient
+
diff --git a/plugin/handler_socket/CMakeLists.txt b/plugin/handler_socket/CMakeLists.txt
new file mode 100644
index 00000000..5a1925b4
--- /dev/null
+++ b/plugin/handler_socket/CMakeLists.txt
@@ -0,0 +1,39 @@
+
+IF(WIN32 OR WITHOUT_SERVER)
+ # Handlersocket does not compile on Windows, compiles but does
+ # not start on FreeBSD.
+ # It is a server plugin and disable it explicitly here.
+ RETURN()
+ENDIF()
+
+MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-deprecated-declarations")
+
+INCLUDE_DIRECTORIES(libhsclient)
+
+# Handlersocket client library. We do not distribute it,
+# it is just compiled in.
+SET(LIBHSCLIENT_SOURCES
+ libhsclient/config.cpp
+ libhsclient/escape.cpp
+ libhsclient/fatal.cpp
+ libhsclient/hstcpcli.cpp
+ libhsclient/socket.cpp
+ libhsclient/string_util.cpp
+)
+ADD_CONVENIENCE_LIBRARY(hsclient ${LIBHSCLIENT_SOURCES})
+# Solaris needs to link some network libraries
+TARGET_LINK_LIBRARIES(hsclient ${LIBSOCKET} ${LIBNLS} ${LIBBIND})
+
+# handlersocket daemon plugin itself.
+SET(HANDLERSOCKET_SOURCES
+ handlersocket/database.cpp
+ handlersocket/handlersocket.cpp
+ handlersocket/hstcpsvr_worker.cpp
+ handlersocket/hstcpsvr.cpp
+)
+MYSQL_ADD_PLUGIN(handlersocket
+ ${HANDLERSOCKET_SOURCES}
+ MODULE_ONLY COMPONENT Server
+ LINK_LIBRARIES hsclient RECOMPILE_FOR_EMBEDDED
+)
+
diff --git a/plugin/handler_socket/ChangeLog b/plugin/handler_socket/ChangeLog
new file mode 100644
index 00000000..793a3993
--- /dev/null
+++ b/plugin/handler_socket/ChangeLog
@@ -0,0 +1,19 @@
+1.0.6 - For MariaDB
+ * Modifications to Makefiles to be part of plugin directory
+ * Compiled by default in max builds
+ * Some minor changes in database.cpp to use the new MariaDB handler
+ interface
+o * Fixed compiler warnings
+
+1.0.6 - 2010-10-29
+ * Changed build instruction (autoreconf/configure/make), removed auto-generated files (Contributed by jmhodges)
+ *
+
+1.0.5 - 2010-10-18
+ * Changed build procedures (using typical configure/make)
+ * Supported 5.5.6
+ * Added status variables
+
+1.0.4 - 2010-08-15
+ * Initial public release
+
diff --git a/plugin/handler_socket/Makefile.am b/plugin/handler_socket/Makefile.am
new file mode 100644
index 00000000..7dff1982
--- /dev/null
+++ b/plugin/handler_socket/Makefile.am
@@ -0,0 +1,88 @@
+
+ACLOCAL_AMFLAGS = -I m4
+
+SUBDIRS = @HANDLERSOCKET_SUBDIRS@
+EXTRA_DIST= plug.in
+
+perl:
+ cd perl-Net-HandlerSocket && perl Makefile.PL && make
+
+install_perl:
+ cd perl-Net-HandlerSocket && make install
+
+rpms: rpm_cli rpm_perl rpm_c
+
+rpm_dir:
+ - mkdir dist
+ - mkdir dist/BUILD dist/RPMS dist/SOURCES dist/SPECS dist/SRPMS
+
+rpm_cli: clean_cli rpm_dir
+ sed -e "s/HANDLERSOCKET_VERSION/$(VERSION)/" \
+ libhsclient/libhsclient.spec.template \
+ > libhsclient/libhsclient.spec
+ tar cvfz dist/libhsclient.tar.gz libhsclient
+ rpmbuild --define "_topdir `pwd`/dist" -ta \
+ dist/libhsclient.tar.gz
+
+rpm_perl: clean_perl rpm_dir
+ sed -e "s/HANDLERSOCKET_VERSION/$(VERSION)/" \
+ perl-Net-HandlerSocket/perl-Net-HandlerSocket.spec.template \
+ > perl-Net-HandlerSocket/perl-Net-HandlerSocket.spec
+ cd perl-Net-HandlerSocket && perl Makefile.PL && make clean && \
+ rm -f Makefile.old
+ tar cvfz dist/perl-Net-HandlerSocket.tar.gz perl-Net-HandlerSocket
+ rpmbuild --define "_topdir `pwd`/dist" -ta \
+ dist/perl-Net-HandlerSocket.tar.gz
+
+rpm_c: clean_c rpm_dir
+ sed -e "s/HANDLERSOCKET_VERSION/$(VERSION)/" \
+ handlersocket/handlersocket.spec.template \
+ > handlersocket/handlersocket.spec
+ sed -e "s|HANDLERSOCKET_MYSQL_INC|$(MYSQL_CFLAGS) $(MYSQL_INC)|" \
+ -e "s|HANDLERSOCKET_MYSQL_LIB|$(MYSQL_LIB)|" \
+ handlersocket/Makefile.plain.template \
+ > handlersocket/Makefile.plain
+ tar cvfz dist/handlersocket.tar.gz handlersocket
+ rpmbuild --define "_topdir `pwd`/dist" -ta \
+ dist/handlersocket.tar.gz
+
+install_rpm_pl:
+ - sudo rpm -e perl-Net-HandlerSocket
+ - sudo rpm -e perl-Net-HandlerSocket-debuginfo
+ make clean
+ make rpm_perl
+ - sudo rpm -U dist/RPMS/*/perl*.rpm
+
+installrpms:
+ - sudo rpm -e handlersocket
+ - sudo rpm -e handlersocket-debuginfo
+ - sudo rpm -e perl-Net-HandlerSocket
+ - sudo rpm -e perl-Net-HandlerSocket-debuginfo
+ - sudo rpm -e libhsclient
+ - sudo rpm -e libhsclient-debuginfo
+ make clean
+ make rpm_cli
+ - sudo rpm -U dist/RPMS/*/libhsclient*.rpm
+ make clean
+ make rpm_perl
+ - sudo rpm -U dist/RPMS/*/perl*.rpm
+ make clean
+ make rpm_c
+ - sudo rpm -U dist/RPMS/*/handlersocket*.rpm
+
+clean_cli:
+ cd libhsclient && make clean
+ cd client && make clean
+
+clean_perl:
+ cd perl-Net-HandlerSocket && perl Makefile.PL && make clean && \
+ rm -f Makefile.old
+
+clean_c:
+ cd handlersocket && make clean
+
+clean_all: clean_cli clean_perl clean_c
+ cd regtest && make clean
+ rm -rf dist/*/*
+ rm -f dist/*.tar.gz
+
diff --git a/plugin/handler_socket/README b/plugin/handler_socket/README
new file mode 100644
index 00000000..9a3bed7a
--- /dev/null
+++ b/plugin/handler_socket/README
@@ -0,0 +1,82 @@
+Notes added by Monty:
+
+This is HandlerSocket version 1.0.6 (See ChangeLog file)
+The original code can be found at:
+
+https://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL
+
+-----------------------------------------------------------------------------
+HandlerSocket plugin for MySQL
+
+Copyright (c) 2010 DeNA Co.,Ltd.
+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 DeNA Co.,Ltd. nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY DeNA Co.,Ltd. "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 DeNA Co.,Ltd. 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.
+
+
+-----------------------------------------------------------------------------
+About HandlerSocket
+
+HandlerSocket is a NoSQL plugin for MySQL. It works as a daemon inside the
+mysqld process, accept tcp connections, and execute requests from clients.
+HandlerSocket does not support SQL queries. Instead, it supports simple CRUD
+operations on tables.
+
+Because of the following reasons, HandlerSocket is much faster than the
+mysqld/libmysql pair in some circumstances:
+
+ - HandlerSocket manipulates data without parsing SQL, which causes less
+ CPU usage.
+ - HandlerSocket reads many requests from clients and executes their
+ requests in bulk, which causes less CPU and disk usage.
+ - HandlerSocket client/server protocol is more compact than the
+ mysql/libmysql pair, which causes less network usage.
+
+The current version of HandlerSocket only works with GNU/Linux. The source
+archive of HandlerSocket includes a C++ and a Perl client libraries.
+Here is a list of client libraries for other languages:
+
+ - PHP
+ http://openpear.org/package/Net_HandlerSocket
+ http://github.com/tz-lom/HSPHP
+ http://code.google.com/p/php-handlersocket/
+ - Java
+ http://code.google.com/p/hs4j/
+ http://code.google.com/p/handlersocketforjava/
+ - Python
+ http://pypi.python.org/pypi/python-handler-socket
+ https://code.launchpad.net/~songofacandy/+junk/pyhandlersocket
+ - Ruby
+ https://github.com/winebarrel/ruby-handlersocket
+ https://github.com/miyucy/handlersocket
+ - JavaScript
+ https://github.com/koichik/node-handlersocket
+ - Scala
+ https://github.com/fujohnwang/hs2client
+
+The home of HandlerSocket is here:
+ https://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL
+
+More documents are available in docs-en/ and docs-ja/ directories.
+
diff --git a/plugin/handler_socket/autogen.sh b/plugin/handler_socket/autogen.sh
new file mode 100755
index 00000000..3b80afd1
--- /dev/null
+++ b/plugin/handler_socket/autogen.sh
@@ -0,0 +1,117 @@
+#!/bin/sh
+
+warn() {
+echo -e "\tWARNING: $@" 1>&2
+}
+
+# init
+
+LIBTOOLIZE=libtoolize
+ACLOCAL=aclocal
+AUTOCONF=autoconf
+AUTOHEADER=autoheader
+AUTOMAKE=automake
+
+case `uname -s` in
+Darwin)
+LIBTOOLIZE=glibtoolize
+;;
+FreeBSD)
+ACLOCAL_ARGS="$ACLOCAL_ARGS -I /usr/local/share/aclocal/"
+;;
+esac
+
+
+# libtoolize
+echo "Searching libtoolize..."
+if [ `which $LIBTOOLIZE` ] ; then
+echo -e "\tFOUND: libtoolize -> $LIBTOOLIZE"
+else
+warn "Cannot Found libtoolize... input libtool command"
+ read LIBTOOLIZE
+ LIBTOOLIZE=`which $LIBTOOLIZE`
+ if [ `which $LIBTOOLIZE` ] ; then
+echo -e "\tSET: libtoolize -> $LIBTOOLIZE"
+ else
+warn "$LIBTOOLIZE: Command not found."
+ exit 1;
+ fi
+fi
+
+# aclocal
+echo "Searching aclocal..."
+if [ `which $ACLOCAL` ] ; then
+echo -e "\tFOUND: aclocal -> $ACLOCAL"
+else
+warn "Cannot Found aclocal... input aclocal command"
+ read ACLOCAL
+ ACLOCAL=`which $ACLOCAL`
+ if [ `which $ACLOCAL` ] ; then
+echo -e "\tSET: aclocal -> $ACLOCAL"
+ else
+warn "$ACLOCAL: Command not found."
+ exit 1;
+ fi
+fi
+
+# automake
+echo "Searching automake..."
+if [ `which $AUTOMAKE` ] ; then
+echo -e "\tFOUND: automake -> $AUTOMAKE"
+else
+warn "Cannot Found automake... input automake command"
+ read AUTOMAKE
+ ACLOCAL=`which $AUTOMAKE`
+ if [ `which $AUTOMAKE` ] ; then
+echo -e "\tSET: automake -> $AUTOMAKE"
+ else
+warn "$AUTOMAKE: Command not found."
+ exit 1;
+ fi
+fi
+
+# autoheader
+echo "Searching autoheader..."
+if [ `which $AUTOHEADER` ] ; then
+echo -e "\tFOUND: autoheader -> $AUTOHEADER"
+else
+warn "Cannot Found autoheader... input autoheader command"
+ read AUTOHEADER
+ ACLOCAL=`which $AUTOHEADER`
+ if [ `which $AUTOHEADER` ] ; then
+echo -e "\tSET: autoheader -> $AUTOHEADER"
+ else
+warn "$AUTOHEADER: Command not found."
+ exit 1;
+ fi
+fi
+
+# autoconf
+echo "Searching autoconf..."
+if [ `which $AUTOCONF` ] ; then
+echo -e "\tFOUND: autoconf -> $AUTOCONF"
+else
+warn "Cannot Found autoconf... input autoconf command"
+ read AUTOCONF
+ ACLOCAL=`which $AUTOCONF`
+ if [ `which $AUTOCONF` ] ; then
+echo -e "\tSET: autoconf -> $AUTOCONF"
+ else
+warn "$AUTOCONF: Command not found."
+ exit 1;
+ fi
+fi
+
+echo "Running libtoolize ..."
+$LIBTOOLIZE --force --copy
+echo "Running aclocal ..."
+$ACLOCAL ${ACLOCAL_ARGS} -I .
+echo "Running autoheader..."
+$AUTOHEADER
+echo "Running automake ..."
+$AUTOMAKE --add-missing --copy
+echo "Running autoconf ..."
+$AUTOCONF
+
+mkdir m4 2> /dev/null
+
diff --git a/plugin/handler_socket/client/Makefile.am b/plugin/handler_socket/client/Makefile.am
new file mode 100644
index 00000000..e89727a7
--- /dev/null
+++ b/plugin/handler_socket/client/Makefile.am
@@ -0,0 +1,24 @@
+CXXFLAGS += -fimplicit-templates
+AM_INCLUDES= -I$(srcdir)/../libhsclient
+bin_PROGRAMS=hsclient
+hsclient_SOURCES= hsclient.cpp
+hsclient_LDFLAGS= -static -L../libhsclient -lhsclient
+hsclient_CXXFLAGS= $(AM_INCLUDES)
+
+hstest: hstest.o
+ $(CXX) $(CXXFLAGS) $(MY_CXXFLAGS) $(LFLAGS) hstest.o \
+ -L../libhsclient/.libs -lhsclient $(MYSQL_LIB) \
+ -o hstest
+
+hstest.o: hstest.cpp
+ $(CXX) $(CXXFLAGS) $(MY_CXXFLAGS) $(MYSQL_INC) $(AM_INCLUDES) \
+ -c hstest.cpp
+
+hslongrun: hslongrun.o
+ $(CXX) $(CXXFLAGS) $(MY_CXXFLAGS) $(LFLAGS) hslongrun.o \
+ -L../libhsclient/.libs -lhsclient $(MYSQL_LIB) \
+ -o hslongrun
+
+hslongrun.o: hslongrun.cpp
+ $(CXX) $(CXXFLAGS) $(MY_CXXFLAGS) $(MYSQL_INC) $(AM_INCLUDES) \
+ -c hslongrun.cpp
diff --git a/plugin/handler_socket/client/hsclient.cpp b/plugin/handler_socket/client/hsclient.cpp
new file mode 100644
index 00000000..0dd8332e
--- /dev/null
+++ b/plugin/handler_socket/client/hsclient.cpp
@@ -0,0 +1,88 @@
+
+// vim:sw=2:ai
+
+#include "hstcpcli.hpp"
+#include "string_util.hpp"
+
+namespace dena {
+
+int
+hstcpcli_main(int argc, char **argv)
+{
+ config conf;
+ parse_args(argc, argv, conf);
+ socket_args sockargs;
+ sockargs.set(conf);
+ hstcpcli_ptr cli = hstcpcli_i::create(sockargs);
+ const std::string dbname = conf.get_str("dbname", "hstest");
+ const std::string table = conf.get_str("table", "hstest_table1");
+ const std::string index = conf.get_str("index", "PRIMARY");
+ const std::string fields = conf.get_str("fields", "k,v");
+ const int limit = conf.get_int("limit", 0);
+ const int skip = conf.get_int("skip", 0);
+ std::vector<std::string> keys;
+ std::vector<string_ref> keyrefs;
+ size_t num_keys = 0;
+ while (true) {
+ const std::string conf_key = std::string("k") + to_stdstring(num_keys);
+ const std::string k = conf.get_str(conf_key, "");
+ const std::string kx = conf.get_str(conf_key, "x");
+ if (k.empty() && kx == "x") {
+ break;
+ }
+ ++num_keys;
+ keys.push_back(k);
+ }
+ for (size_t i = 0; i < keys.size(); ++i) {
+ const string_ref ref(keys[i].data(), keys[i].size());
+ keyrefs.push_back(ref);
+ }
+ const std::string op = conf.get_str("op", "=");
+ const string_ref op_ref(op.data(), op.size());
+ cli->request_buf_open_index(0, dbname.c_str(), table.c_str(),
+ index.c_str(), fields.c_str());
+ cli->request_buf_exec_generic(0, op_ref, num_keys == 0 ? 0 : &keyrefs[0],
+ num_keys, limit, skip, string_ref(), 0, 0);
+ int code = 0;
+ size_t numflds = 0;
+ do {
+ if (cli->request_send() != 0) {
+ fprintf(stderr, "request_send: %s\n", cli->get_error().c_str());
+ break;
+ }
+ if ((code = cli->response_recv(numflds)) != 0) {
+ fprintf(stderr, "response_recv: %s\n", cli->get_error().c_str());
+ break;
+ }
+ } while (false);
+ cli->response_buf_remove();
+ do {
+ if ((code = cli->response_recv(numflds)) != 0) {
+ fprintf(stderr, "response_recv: %s\n", cli->get_error().c_str());
+ break;
+ }
+ while (true) {
+ const string_ref *const row = cli->get_next_row();
+ if (row == 0) {
+ break;
+ }
+ printf("REC:");
+ for (size_t i = 0; i < numflds; ++i) {
+ const std::string val(row[i].begin(), row[i].size());
+ printf(" %s", val.c_str());
+ }
+ printf("\n");
+ }
+ } while (false);
+ cli->response_buf_remove();
+ return 0;
+}
+
+};
+
+int
+main(int argc, char **argv)
+{
+ return dena::hstcpcli_main(argc, argv);
+}
+
diff --git a/plugin/handler_socket/client/hslongrun.cpp b/plugin/handler_socket/client/hslongrun.cpp
new file mode 100644
index 00000000..b7c02951
--- /dev/null
+++ b/plugin/handler_socket/client/hslongrun.cpp
@@ -0,0 +1,1041 @@
+
+// vim:sw=2:ai
+
+#include <signal.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <string.h>
+#include <vector>
+#include <map>
+#include <stdlib.h>
+#include <memory>
+#include <errno.h>
+#include <mysql.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "util.hpp"
+#include "auto_ptrcontainer.hpp"
+#include "socket.hpp"
+#include "hstcpcli.hpp"
+#include "string_util.hpp"
+#include "mutex.hpp"
+
+namespace dena {
+
+struct auto_mysql : private noncopyable {
+ auto_mysql() : db(0) {
+ reset();
+ }
+ ~auto_mysql() {
+ if (db) {
+ mysql_close(db);
+ }
+ }
+ void reset() {
+ if (db) {
+ mysql_close(db);
+ }
+ if ((db = mysql_init(0)) == 0) {
+ fatal_abort("failed to initialize mysql client");
+ }
+ }
+ operator MYSQL *() const { return db; }
+ private:
+ MYSQL *db;
+};
+
+struct auto_mysql_res : private noncopyable {
+ auto_mysql_res(MYSQL *db) {
+ res = mysql_store_result(db);
+ }
+ ~auto_mysql_res() {
+ if (res) {
+ mysql_free_result(res);
+ }
+ }
+ operator MYSQL_RES *() const { return res; }
+ private:
+ MYSQL_RES *res;
+};
+
+struct auto_mysql_stmt : private noncopyable {
+ auto_mysql_stmt(MYSQL *db) {
+ stmt = mysql_stmt_init(db);
+ }
+ ~auto_mysql_stmt() {
+ if (stmt) {
+ mysql_stmt_close(stmt);
+ }
+ }
+ operator MYSQL_STMT *() const { return stmt; }
+ private:
+ MYSQL_STMT *stmt;
+};
+
+double
+gettimeofday_double()
+{
+ struct timeval tv = { };
+ if (gettimeofday(&tv, 0) != 0) {
+ fatal_abort("gettimeofday");
+ }
+ return static_cast<double>(tv.tv_usec) / 1000000 + tv.tv_sec;
+}
+
+struct record_value {
+ mutex lock;
+ bool deleted;
+ bool unknown_state;
+ std::string key;
+ std::vector<std::string> values;
+ record_value() : deleted(true), unknown_state(false) { }
+};
+
+struct hs_longrun_shared {
+ config conf;
+ socket_args arg;
+ int verbose;
+ long num_threads;
+ int usleep;
+ volatile mutable int running;
+ auto_ptrcontainer< std::vector<record_value *> > records;
+ hs_longrun_shared() : verbose(0), num_threads(0), usleep(0), running(1) { }
+};
+
+struct thread_base {
+ thread_base() : need_join(false), stack_size(256 * 1024) { }
+ virtual ~thread_base() {
+ join();
+ }
+ virtual void run() = 0;
+ void start() {
+ if (!start_nothrow()) {
+ fatal_abort("thread::start");
+ }
+ }
+ bool start_nothrow() {
+ if (need_join) {
+ return need_join; /* true */
+ }
+ void *const arg = this;
+ pthread_attr_t attr;
+ if (pthread_attr_init(&attr) != 0) {
+ fatal_abort("pthread_attr_init");
+ }
+ if (pthread_attr_setstacksize(&attr, stack_size) != 0) {
+ fatal_abort("pthread_attr_setstacksize");
+ }
+ const int r = pthread_create(&thr, &attr, thread_main, arg);
+ if (pthread_attr_destroy(&attr) != 0) {
+ fatal_abort("pthread_attr_destroy");
+ }
+ if (r != 0) {
+ return need_join; /* false */
+ }
+ need_join = true;
+ return need_join; /* true */
+ }
+ void join() {
+ if (!need_join) {
+ return;
+ }
+ int e = 0;
+ if ((e = pthread_join(thr, 0)) != 0) {
+ fatal_abort("pthread_join");
+ }
+ need_join = false;
+ }
+ private:
+ static void *thread_main(void *arg) {
+ thread_base *p = static_cast<thread_base *>(arg);
+ p->run();
+ return 0;
+ }
+ private:
+ pthread_t thr;
+ bool need_join;
+ size_t stack_size;
+};
+
+struct hs_longrun_stat {
+ unsigned long long verify_error_count;
+ unsigned long long runtime_error_count;
+ unsigned long long unknown_count;
+ unsigned long long success_count;
+ hs_longrun_stat()
+ : verify_error_count(0), runtime_error_count(0),
+ unknown_count(0), success_count(0) { }
+ void add(const hs_longrun_stat& x) {
+ verify_error_count += x.verify_error_count;
+ runtime_error_count += x.runtime_error_count;
+ unknown_count += x.unknown_count;
+ success_count += x.success_count;
+ }
+};
+
+struct hs_longrun_thread_base : public thread_base {
+ struct arg_type {
+ int id;
+ std::string worker_type;
+ char op;
+ int lock_flag;
+ const hs_longrun_shared& sh;
+ arg_type(int id, const std::string& worker_type, char op, int lock_flag,
+ const hs_longrun_shared& sh)
+ : id(id), worker_type(worker_type), op(op), lock_flag(lock_flag),
+ sh(sh) { }
+ };
+ arg_type arg;
+ hs_longrun_stat stat;
+ drand48_data randbuf;
+ unsigned int seed;
+ hs_longrun_thread_base(const arg_type& arg)
+ : arg(arg), seed(0) {
+ seed = time(0) + arg.id + 1;
+ srand48_r(seed, &randbuf);
+ }
+ virtual ~hs_longrun_thread_base() { }
+ virtual void run() = 0;
+ size_t rand_record() {
+ double v = 0;
+ drand48_r(&randbuf, &v);
+ const size_t sz = arg.sh.records.size();
+ size_t r = size_t(v * sz);
+ if (r >= sz) {
+ r = 0;
+ }
+ return r;
+ }
+ int verify_update(const std::string& k, const std::string& v1,
+ const std::string& v2, const std::string& v3, record_value& rec,
+ uint32_t num_rows, bool cur_unknown_state);
+ int verify_read(const std::string& k, uint32_t num_rows, uint32_t num_flds,
+ const std::string rrec[4], record_value& rec);
+ int verify_readnolock(const std::string& k, uint32_t num_rows,
+ uint32_t num_flds, const std::string rrec[4]);
+};
+
+int
+hs_longrun_thread_base::verify_update(const std::string& k,
+ const std::string& v1, const std::string& v2, const std::string& v3,
+ record_value& rec, uint32_t num_rows, bool cur_unknown_state)
+{
+ const bool op_success = num_rows == 1;
+ int ret = 0;
+ if (!rec.unknown_state) {
+ if (!rec.deleted && !op_success) {
+ ++stat.verify_error_count;
+ if (arg.sh.verbose > 0) {
+ fprintf(stderr, "VERIFY_ERROR: %s wid=%d k=%s "
+ "unexpected_update_failure\n",
+ arg.worker_type.c_str(), arg.id, k.c_str());
+ }
+ ret = 1;
+ } else if (rec.deleted && op_success) {
+ ++stat.verify_error_count;
+ if (arg.sh.verbose > 0) {
+ fprintf(stderr, "VERIFY_ERROR: %s wid=%d k=%s "
+ "unexpected_update_success\n",
+ arg.worker_type.c_str(), arg.id, k.c_str());
+ }
+ ret = 1;
+ }
+ }
+ if (op_success) {
+ rec.values.resize(4);
+ rec.values[0] = k;
+ rec.values[1] = v1;
+ rec.values[2] = v2;
+ rec.values[3] = v3;
+ if (ret == 0 && !rec.unknown_state) {
+ ++stat.success_count;
+ }
+ }
+ rec.unknown_state = cur_unknown_state;
+ if (arg.sh.verbose >= 100 && ret == 0) {
+ fprintf(stderr, "%s %s %s %s %s\n", arg.worker_type.c_str(),
+ k.c_str(), v1.c_str(), v2.c_str(), v3.c_str());
+ }
+ return ret;
+}
+
+int
+hs_longrun_thread_base::verify_read(const std::string& k,
+ uint32_t num_rows, uint32_t num_flds, const std::string rrec[4],
+ record_value& rec)
+{
+ const bool op_success = num_rows != 0;
+ int ret = 0;
+ if (!rec.unknown_state) {
+ if (!rec.deleted && !op_success) {
+ ++stat.verify_error_count;
+ if (arg.sh.verbose > 0) {
+ fprintf(stderr, "VERIFY_ERROR: %s wid=%d k=%s "
+ "unexpected_read_failure\n",
+ arg.worker_type.c_str(), arg.id, k.c_str());
+ }
+ ret = 1;
+ } else if (rec.deleted && op_success) {
+ ++stat.verify_error_count;
+ if (arg.sh.verbose > 0) {
+ fprintf(stderr, "VERIFY_ERROR: %s wid=%d k=%s "
+ "unexpected_read_success\n",
+ arg.worker_type.c_str(), arg.id, k.c_str());
+ }
+ ret = 1;
+ } else if (num_flds != 4) {
+ ++stat.verify_error_count;
+ if (arg.sh.verbose > 0) {
+ fprintf(stderr, "VERIFY_ERROR: %s wid=%d k=%s "
+ "unexpected_read_fldnum %d\n",
+ arg.worker_type.c_str(), arg.id, k.c_str(),
+ static_cast<int>(num_flds));
+ }
+ ret = 1;
+ } else if (rec.deleted) {
+ /* nothing to verify */
+ } else {
+ int diff = 0;
+ for (size_t i = 0; i < 4; ++i) {
+ if (rec.values[i] == rrec[i]) {
+ /* ok */
+ } else {
+ diff = 1;
+ }
+ }
+ if (diff) {
+ std::string mess;
+ for (size_t i = 0; i < 4; ++i) {
+ const std::string& expected = rec.values[i];
+ const std::string& val = rrec[i];
+ mess += " " + val + "/" + expected;
+ }
+ if (arg.sh.verbose > 0) {
+ fprintf(stderr, "VERIFY_ERROR: %s wid=%d k=%s "
+ "unexpected_read_value %s\n",
+ arg.worker_type.c_str(), arg.id, k.c_str(), mess.c_str());
+ }
+ ret = 1;
+ }
+ }
+ }
+ if (arg.sh.verbose >= 100 && ret == 0) {
+ fprintf(stderr, "%s %s\n", arg.worker_type.c_str(), k.c_str());
+ }
+ if (ret == 0 && !rec.unknown_state) {
+ ++stat.success_count;
+ }
+ return ret;
+}
+
+int
+hs_longrun_thread_base::verify_readnolock(const std::string& k,
+ uint32_t num_rows, uint32_t num_flds, const std::string rrec[4])
+{
+ int ret = 0;
+ if (num_rows != 1 || num_flds != 4) {
+ ++stat.verify_error_count;
+ if (arg.sh.verbose > 0) {
+ fprintf(stderr, "VERIFY_ERROR: %s wid=%d k=%s "
+ "unexpected_read_failure\n",
+ arg.worker_type.c_str(), arg.id, k.c_str());
+ }
+ ret = 1;
+ }
+ if (arg.sh.verbose >= 100 && ret == 0) {
+ fprintf(stderr, "%s -> %s %s %s %s %s\n", arg.worker_type.c_str(),
+ k.c_str(), rrec[0].c_str(), rrec[1].c_str(), rrec[2].c_str(),
+ rrec[3].c_str());
+ }
+ if (ret == 0) {
+ ++stat.success_count;
+ }
+ return ret;
+}
+
+struct hs_longrun_thread_hs : public hs_longrun_thread_base {
+ hs_longrun_thread_hs(const arg_type& arg)
+ : hs_longrun_thread_base(arg) { }
+ void run();
+ int check_hs_error(const char *mess, record_value *rec);
+ int op_insert(record_value& rec);
+ int op_delete(record_value& rec);
+ int op_update(record_value& rec);
+ int op_read(record_value& rec);
+ int op_readnolock(int k);
+ hstcpcli_ptr cli;
+ socket_args sockargs;
+};
+
+struct lock_guard : noncopyable {
+ lock_guard(mutex& mtx) : mtx(mtx) {
+ mtx.lock();
+ }
+ ~lock_guard() {
+ mtx.unlock();
+ }
+ mutex& mtx;
+};
+
+string_ref
+to_string_ref(const std::string& s)
+{
+ return string_ref(s.data(), s.size());
+}
+
+std::string
+to_string(const string_ref& s)
+{
+ return std::string(s.begin(), s.size());
+}
+
+void
+hs_longrun_thread_hs::run()
+{
+ config c = arg.sh.conf;
+ if (arg.op == 'R' || arg.op == 'N') {
+ c["port"] = to_stdstring(arg.sh.conf.get_int("hsport", 9998));
+ } else {
+ c["port"] = to_stdstring(arg.sh.conf.get_int("hsport_wr", 9999));
+ }
+ sockargs.set(c);
+
+ while (arg.sh.running) {
+ if (cli.get() == 0 || !cli->stable_point()) {
+ cli = hstcpcli_i::create(sockargs);
+ if (check_hs_error("connect", 0) != 0) {
+ cli.reset();
+ continue;
+ }
+ cli->request_buf_open_index(0, "hstestdb", "hstesttbl", "PRIMARY",
+ "k,v1,v2,v3", "k,v1,v2,v3");
+ cli->request_send();
+ if (check_hs_error("openindex_send", 0) != 0) {
+ cli.reset();
+ continue;
+ }
+ size_t num_flds = 0;
+ cli->response_recv(num_flds);
+ if (check_hs_error("openindex_recv", 0) != 0) {
+ cli.reset();
+ continue;
+ }
+ cli->response_buf_remove();
+ }
+ const size_t rec_id = rand_record();
+ if (arg.lock_flag) {
+ record_value& rec = *arg.sh.records[rec_id];
+ lock_guard g(rec.lock);
+ int e = 0;
+ switch (arg.op) {
+ case 'I':
+ e = op_insert(rec);
+ break;
+ case 'D':
+ e = op_delete(rec);
+ break;
+ case 'U':
+ e = op_update(rec);
+ break;
+ case 'R':
+ e = op_read(rec);
+ break;
+ default:
+ break;
+ }
+ } else {
+ int e = 0;
+ switch (arg.op) {
+ case 'N':
+ e = op_readnolock(rec_id);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+int
+hs_longrun_thread_hs::op_insert(record_value& rec)
+{
+ const std::string k = rec.key;
+ const std::string v1 = "iv1_" + k + "_" + to_stdstring(arg.id);
+ const std::string v2 = "iv2_" + k + "_" + to_stdstring(arg.id);
+ const std::string v3 = "iv3_" + k + "_" + to_stdstring(arg.id);
+ const string_ref op_ref("+", 1);
+ const string_ref op_args[4] = {
+ to_string_ref(k),
+ to_string_ref(v1),
+ to_string_ref(v2),
+ to_string_ref(v3)
+ };
+ cli->request_buf_exec_generic(0, op_ref, op_args, 4, 1, 0,
+ string_ref(), 0, 0, 0, 0);
+ cli->request_send();
+ if (check_hs_error("op_insert_send", &rec) != 0) { return 1; }
+ size_t numflds = 0;
+ cli->response_recv(numflds);
+ if (arg.sh.verbose > 10) {
+ const string_ref *row = cli->get_next_row();
+ fprintf(stderr, "HS op=+ errrcode=%d errmess=[%s]\n", cli->get_error_code(),
+ row ? to_string(row[0]).c_str() : "");
+ }
+ const bool op_success = cli->get_error_code() == 0;
+ int ret = 0;
+ if (!rec.unknown_state) {
+ if (rec.deleted && !op_success) {
+ ++stat.verify_error_count;
+ if (arg.sh.verbose > 0) {
+ fprintf(stderr, "VERIFY_ERROR: %s wid=%d k=%s "
+ "unexpected_insert_failure\n",
+ arg.worker_type.c_str(), arg.id, k.c_str());
+ }
+ ret = 1;
+ } else if (!rec.deleted && op_success) {
+ ++stat.verify_error_count;
+ if (arg.sh.verbose > 0) {
+ fprintf(stderr, "VERIFY_ERROR: %s wid=%d k=%s "
+ "unexpected_insert_success\n",
+ arg.worker_type.c_str(), arg.id, k.c_str());
+ }
+ ret = 1;
+ }
+ } else {
+ ++stat.unknown_count;
+ }
+ if (op_success) {
+ rec.values.resize(4);
+ rec.values[0] = k;
+ rec.values[1] = v1;
+ rec.values[2] = v2;
+ rec.values[3] = v3;
+ rec.deleted = false;
+ if (arg.sh.verbose >= 100 && ret == 0) {
+ fprintf(stderr, "HS_INSERT %s %s %s %s\n", k.c_str(), v1.c_str(),
+ v2.c_str(), v3.c_str());
+ }
+ if (ret == 0 && !rec.unknown_state) {
+ ++stat.success_count;
+ }
+ rec.unknown_state = false;
+ }
+ cli->response_buf_remove();
+ return ret;
+}
+
+int
+hs_longrun_thread_hs::op_delete(record_value& rec)
+{
+ const std::string k = rec.key;
+ const string_ref op_ref("=", 1);
+ const string_ref op_args[1] = {
+ to_string_ref(k),
+ };
+ const string_ref modop_ref("D", 1);
+ cli->request_buf_exec_generic(0, op_ref, op_args, 1, 1, 0,
+ modop_ref, 0, 0, 0, 0);
+ cli->request_send();
+ if (check_hs_error("op_delete_send", &rec) != 0) { return 1; }
+ size_t numflds = 0;
+ cli->response_recv(numflds);
+ if (check_hs_error("op_delete_recv", &rec) != 0) { return 1; }
+ const string_ref *row = cli->get_next_row();
+ const bool op_success = (numflds > 0 && row != 0 &&
+ to_string(row[0]) == "1");
+ int ret = 0;
+ if (!rec.unknown_state) {
+ if (!rec.deleted && !op_success) {
+ ++stat.verify_error_count;
+ if (arg.sh.verbose > 0) {
+ fprintf(stderr, "VERIFY_ERROR: %s wid=%d k=%s "
+ "unexpected_delete_failure\n",
+ arg.worker_type.c_str(), arg.id, k.c_str());
+ }
+ ret = 1;
+ } else if (rec.deleted && op_success) {
+ ++stat.verify_error_count;
+ if (arg.sh.verbose > 0) {
+ fprintf(stderr, "VERIFY_ERROR: %s wid=%d k=%s "
+ "unexpected_delete_success\n",
+ arg.worker_type.c_str(), arg.id, k.c_str());
+ }
+ ret = 1;
+ }
+ }
+ cli->response_buf_remove();
+ if (op_success) {
+ rec.deleted = true;
+ if (ret == 0 && !rec.unknown_state) {
+ ++stat.success_count;
+ }
+ rec.unknown_state = false;
+ }
+ if (arg.sh.verbose >= 100 && ret == 0) {
+ fprintf(stderr, "HS_DELETE %s\n", k.c_str());
+ }
+ return ret;
+}
+
+int
+hs_longrun_thread_hs::op_update(record_value& rec)
+{
+ const std::string k = rec.key;
+ const std::string v1 = "uv1_" + k + "_" + to_stdstring(arg.id);
+ const std::string v2 = "uv2_" + k + "_" + to_stdstring(arg.id);
+ const std::string v3 = "uv3_" + k + "_" + to_stdstring(arg.id);
+ const string_ref op_ref("=", 1);
+ const string_ref op_args[1] = {
+ to_string_ref(k),
+ };
+ const string_ref modop_ref("U", 1);
+ const string_ref modop_args[4] = {
+ to_string_ref(k),
+ to_string_ref(v1),
+ to_string_ref(v2),
+ to_string_ref(v3)
+ };
+ cli->request_buf_exec_generic(0, op_ref, op_args, 1, 1, 0,
+ modop_ref, modop_args, 4, 0, 0);
+ cli->request_send();
+ if (check_hs_error("op_update_send", &rec) != 0) { return 1; }
+ size_t numflds = 0;
+ cli->response_recv(numflds);
+ if (check_hs_error("op_update_recv", &rec) != 0) { return 1; }
+ const string_ref *row = cli->get_next_row();
+ uint32_t num_rows = row
+ ? atoi_uint32_nocheck(row[0].begin(), row[0].end()) : 0;
+ cli->response_buf_remove();
+ const bool cur_unknown_state = (num_rows == 1);
+ return verify_update(k, v1, v2, v3, rec, num_rows, cur_unknown_state);
+}
+
+int
+hs_longrun_thread_hs::op_read(record_value& rec)
+{
+ const std::string k = rec.key;
+ const string_ref op_ref("=", 1);
+ const string_ref op_args[1] = {
+ to_string_ref(k),
+ };
+ cli->request_buf_exec_generic(0, op_ref, op_args, 1, 1, 0,
+ string_ref(), 0, 0, 0, 0);
+ cli->request_send();
+ if (check_hs_error("op_read_send", 0) != 0) { return 1; }
+ size_t num_flds = 0;
+ size_t num_rows = 0;
+ cli->response_recv(num_flds);
+ if (check_hs_error("op_read_recv", 0) != 0) { return 1; }
+ const string_ref *row = cli->get_next_row();
+ std::string rrec[4];
+ if (row != 0 && num_flds == 4) {
+ for (int i = 0; i < 4; ++i) {
+ rrec[i] = to_string(row[i]);
+ }
+ ++num_rows;
+ }
+ row = cli->get_next_row();
+ if (row != 0) {
+ ++num_rows;
+ }
+ cli->response_buf_remove();
+ return verify_read(k, num_rows, num_flds, rrec, rec);
+}
+
+int
+hs_longrun_thread_hs::op_readnolock(int key)
+{
+ const std::string k = to_stdstring(key);
+ const string_ref op_ref("=", 1);
+ const string_ref op_args[1] = {
+ to_string_ref(k),
+ };
+ cli->request_buf_exec_generic(0, op_ref, op_args, 1, 1, 0,
+ string_ref(), 0, 0, 0, 0);
+ cli->request_send();
+ if (check_hs_error("op_read_send", 0) != 0) { return 1; }
+ size_t num_flds = 0;
+ size_t num_rows = 0;
+ cli->response_recv(num_flds);
+ if (check_hs_error("op_read_recv", 0) != 0) { return 1; }
+ const string_ref *row = cli->get_next_row();
+ std::string rrec[4];
+ if (row != 0 && num_flds == 4) {
+ for (int i = 0; i < 4; ++i) {
+ rrec[i] = to_string(row[i]);
+ }
+ ++num_rows;
+ }
+ row = cli->get_next_row();
+ if (row != 0) {
+ ++num_rows;
+ }
+ cli->response_buf_remove();
+ return verify_readnolock(k, num_rows, num_flds, rrec);
+}
+
+int
+hs_longrun_thread_hs::check_hs_error(const char *mess, record_value *rec)
+{
+ const int err = cli->get_error_code();
+ if (err == 0) {
+ return 0;
+ }
+ ++stat.runtime_error_count;
+ if (arg.sh.verbose > 0) {
+ const std::string estr = cli->get_error();
+ fprintf(stderr, "RUNTIME_ERROR: op=%c wid=%d %s: %d %s\n",
+ arg.op, arg.id, mess, err, estr.c_str());
+ }
+ if (rec) {
+ rec->unknown_state = true;
+ }
+ return 1;
+}
+
+struct hs_longrun_thread_my : public hs_longrun_thread_base {
+ hs_longrun_thread_my(const arg_type& arg)
+ : hs_longrun_thread_base(arg), connected(false) { }
+ void run();
+ void show_mysql_error(const char *mess, record_value *rec);
+ int op_insert(record_value& rec);
+ int op_delete(record_value& rec);
+ int op_update(record_value& rec);
+ int op_delins(record_value& rec);
+ int op_read(record_value& rec);
+ auto_mysql db;
+ bool connected;
+};
+
+void
+hs_longrun_thread_my::run()
+{
+ const std::string mysql_host = arg.sh.conf.get_str("host", "localhost");
+ const std::string mysql_user = arg.sh.conf.get_str("mysqluser", "root");
+ const std::string mysql_passwd = arg.sh.conf.get_str("mysqlpass", "");
+ const std::string mysql_dbname = "hstestdb";
+
+ while (arg.sh.running) {
+ if (!connected) {
+ if (!mysql_real_connect(db, mysql_host.c_str(), mysql_user.c_str(),
+ mysql_passwd.c_str(), mysql_dbname.c_str(), mysql_port, 0, 0)) {
+ show_mysql_error("mysql_real_connect", 0);
+ continue;
+ }
+ }
+ connected = true;
+ const size_t rec_id = rand_record();
+ record_value& rec = *arg.sh.records[rec_id];
+ lock_guard g(rec.lock);
+ int e = 0;
+ switch (arg.op) {
+ #if 0
+ case 'I':
+ e = op_insert(rec);
+ break;
+ case 'D':
+ e = op_delete(rec);
+ break;
+ case 'U':
+ e = op_update(rec);
+ break;
+ #endif
+ case 'T':
+ e = op_delins(rec);
+ break;
+ case 'R':
+ e = op_read(rec);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+int
+hs_longrun_thread_my::op_delins(record_value& rec)
+{
+ const std::string k = rec.key;
+ const std::string v1 = "div1_" + k + "_" + to_stdstring(arg.id);
+ const std::string v2 = "div2_" + k + "_" + to_stdstring(arg.id);
+ const std::string v3 = "div3_" + k + "_" + to_stdstring(arg.id);
+ int success = 0;
+ bool cur_unknown_state = false;
+ do {
+ char query[1024];
+ #if 1
+ if (mysql_query(db, "begin") != 0) {
+ if (arg.sh.verbose >= 20) {
+ fprintf(stderr, "mysql: e=[%s] q=[%s]\n", mysql_error(db), "begin");
+ }
+ break;
+ }
+ #endif
+ cur_unknown_state = true;
+ snprintf(query, 1024,
+ "delete from hstesttbl where k = '%s'", k.c_str());
+ if (mysql_query(db, query) != 0) {
+ if (arg.sh.verbose >= 20) {
+ fprintf(stderr, "mysql: e=[%s] q=[%s]\n", mysql_error(db), query);
+ }
+ break;
+ }
+ if (mysql_affected_rows(db) != 1) {
+ if (arg.sh.verbose >= 20) {
+ fprintf(stderr, "mysql: notfound: [%s]\n", query);
+ }
+ break;
+ }
+ snprintf(query, 1024,
+ "insert into hstesttbl values ('%s', '%s', '%s', '%s')",
+ k.c_str(), v1.c_str(), v2.c_str(), v3.c_str());
+ if (mysql_query(db, query) != 0) {
+ if (arg.sh.verbose >= 20) {
+ fprintf(stderr, "mysql: e=[%s] q=[%s]\n", mysql_error(db), query);
+ }
+ break;
+ }
+ #if 1
+ if (mysql_query(db, "commit") != 0) {
+ if (arg.sh.verbose >= 20) {
+ fprintf(stderr, "mysql: e=[%s] q=[%s]\n", mysql_error(db), "commit");
+ }
+ break;
+ }
+ #endif
+ success = true;
+ cur_unknown_state = false;
+ } while (false);
+ return verify_update(k, v1, v2, v3, rec, (success != 0), cur_unknown_state);
+}
+
+int
+hs_longrun_thread_my::op_read(record_value& rec)
+{
+ const std::string k = rec.key;
+ char query[1024] = { 0 };
+ const int len = snprintf(query, 1024,
+ "select k,v1,v2,v3 from hstesttbl where k='%s'", k.c_str());
+ const int r = mysql_real_query(db, query, len > 0 ? len : 0);
+ if (r != 0) {
+ show_mysql_error(query, 0);
+ return 1;
+ }
+ MYSQL_ROW row = 0;
+ unsigned long *lengths = 0;
+ unsigned int num_rows = 0;
+ unsigned int num_flds = 0;
+ auto_mysql_res res(db);
+ std::string rrec[4];
+ if (res != 0) {
+ num_flds = mysql_num_fields(res);
+ row = mysql_fetch_row(res);
+ if (row != 0) {
+ lengths = mysql_fetch_lengths(res);
+ if (num_flds == 4) {
+ for (int i = 0; i < 4; ++i) {
+ rrec[i] = std::string(row[i], lengths[i]);
+ }
+ }
+ ++num_rows;
+ row = mysql_fetch_row(res);
+ if (row != 0) {
+ ++num_rows;
+ }
+ }
+ }
+ return verify_read(k, num_rows, num_flds, rrec, rec);
+}
+
+void
+hs_longrun_thread_my::show_mysql_error(const char *mess, record_value *rec)
+{
+ ++stat.runtime_error_count;
+ if (arg.sh.verbose > 0) {
+ fprintf(stderr, "RUNTIME_ERROR: op=%c wid=%d [%s]: %s\n",
+ arg.op, arg.id, mess, mysql_error(db));
+ }
+ if (rec) {
+ rec->unknown_state = true;
+ }
+ db.reset();
+ connected = false;
+}
+
+void
+mysql_do(MYSQL *db, const char *query)
+{
+ if (mysql_real_query(db, query, strlen(query)) != 0) {
+ fprintf(stderr, "mysql: e=[%s] q=[%s]\n", mysql_error(db), query);
+ fatal_abort("mysql_do");
+ }
+}
+
+void
+hs_longrun_init_table(const config& conf, int num_prepare,
+ hs_longrun_shared& shared)
+{
+ const std::string mysql_host = conf.get_str("host", "localhost");
+ const std::string mysql_user = conf.get_str("mysqluser", "root");
+ const std::string mysql_passwd = conf.get_str("mysqlpass", "");
+ const std::string mysql_dbname = "";
+ auto_mysql db;
+ if (!mysql_real_connect(db, mysql_host.c_str(), mysql_user.c_str(),
+ mysql_passwd.c_str(), mysql_dbname.c_str(), mysql_port, 0, 0)) {
+ fprintf(stderr, "mysql: error=[%s]\n", mysql_error(db));
+ fatal_abort("hs_longrun_init_table");
+ }
+ mysql_do(db, "drop database if exists hstestdb");
+ mysql_do(db, "create database hstestdb");
+ mysql_do(db, "use hstestdb");
+ mysql_do(db,
+ "create table hstesttbl ("
+ "k int primary key,"
+ "v1 varchar(32) not null,"
+ "v2 varchar(32) not null,"
+ "v3 varchar(32) not null"
+ ") character set utf8 collate utf8_bin engine = innodb");
+ for (int i = 0; i < num_prepare; ++i) {
+ const std::string i_str = to_stdstring(i);
+ const std::string v1 = "pv1_" + i_str;
+ const std::string v2 = "pv2_" + i_str;
+ const std::string v3 = "pv3_" + i_str;
+ char buf[1024];
+ snprintf(buf, 1024, "insert into hstesttbl(k, v1, v2, v3) values"
+ "(%d, '%s', '%s', '%s')", i, v1.c_str(), v2.c_str(), v3.c_str());
+ mysql_do(db, buf);
+ record_value *rec = shared.records[i];
+ rec->key = i_str;
+ rec->values.resize(4);
+ rec->values[0] = i_str;
+ rec->values[1] = v1;
+ rec->values[2] = v2;
+ rec->values[3] = v3;
+ rec->deleted = false;
+ }
+}
+
+int
+hs_longrun_main(int argc, char **argv)
+{
+ hs_longrun_shared shared;
+ parse_args(argc, argv, shared.conf);
+ shared.conf["host"] = shared.conf.get_str("host", "localhost");
+ shared.verbose = shared.conf.get_int("verbose", 1);
+ const int table_size = shared.conf.get_int("table_size", 10000);
+ for (int i = 0; i < table_size; ++i) {
+ std::auto_ptr<record_value> rec(new record_value());
+ rec->key = to_stdstring(i);
+ shared.records.push_back_ptr(rec);
+ }
+ mysql_library_init(0, 0, 0);
+ const int duration = shared.conf.get_int("duration", 10);
+ const int num_hsinsert = shared.conf.get_int("num_hsinsert", 10);
+ const int num_hsdelete = shared.conf.get_int("num_hsdelete", 10);
+ const int num_hsupdate = shared.conf.get_int("num_hsupdate", 10);
+ const int num_hsread = shared.conf.get_int("num_hsread", 10);
+ const int num_myread = shared.conf.get_int("num_myread", 10);
+ const int num_mydelins = shared.conf.get_int("num_mydelins", 10);
+ int num_hsreadnolock = shared.conf.get_int("num_hsreadnolock", 10);
+ const bool always_filled = (num_hsinsert == 0 && num_hsdelete == 0);
+ if (!always_filled) {
+ num_hsreadnolock = 0;
+ }
+ hs_longrun_init_table(shared.conf, always_filled ? table_size : 0,
+ shared);
+ /* create worker threads */
+ static const struct thrtmpl_type {
+ const char *type; char op; int num; int hs; int lock;
+ } thrtmpl[] = {
+ { "hsinsert", 'I', num_hsinsert, 1, 1 },
+ { "hsdelete", 'D', num_hsdelete, 1, 1 },
+ { "hsupdate", 'U', num_hsupdate, 1, 1 },
+ { "hsread", 'R', num_hsread, 1, 1 },
+ { "hsreadnolock", 'N', num_hsreadnolock, 1, 0 },
+ { "myread", 'R', num_myread, 0, 1 },
+ { "mydelins", 'T', num_mydelins, 0, 1 },
+ };
+ typedef auto_ptrcontainer< std::vector<hs_longrun_thread_base *> > thrs_type;
+ thrs_type thrs;
+ for (size_t i = 0; i < sizeof(thrtmpl)/sizeof(thrtmpl[0]); ++i) {
+ const thrtmpl_type& e = thrtmpl[i];
+ for (int j = 0; j < e.num; ++j) {
+ int id = thrs.size();
+ const hs_longrun_thread_hs::arg_type arg(id, e.type, e.op, e.lock,
+ shared);
+ std::auto_ptr<hs_longrun_thread_base> thr;
+ if (e.hs) {
+ thr.reset(new hs_longrun_thread_hs(arg));
+ } else {
+ thr.reset(new hs_longrun_thread_my(arg));
+ }
+ thrs.push_back_ptr(thr);
+ }
+ }
+ shared.num_threads = thrs.size();
+ /* start threads */
+ fprintf(stderr, "START\n");
+ shared.running = 1;
+ for (size_t i = 0; i < thrs.size(); ++i) {
+ thrs[i]->start();
+ }
+ /* wait */
+ sleep(duration);
+ /* stop thread */
+ shared.running = 0;
+ for (size_t i = 0; i < thrs.size(); ++i) {
+ thrs[i]->join();
+ }
+ fprintf(stderr, "DONE\n");
+ /* summary */
+ typedef std::map<std::string, hs_longrun_stat> stat_map;
+ stat_map sm;
+ for (size_t i = 0; i < thrs.size(); ++i) {
+ hs_longrun_thread_base *const thr = thrs[i];
+ const std::string wt = thr->arg.worker_type;
+ hs_longrun_stat& v = sm[wt];
+ v.add(thr->stat);
+ }
+ hs_longrun_stat total;
+ for (stat_map::const_iterator i = sm.begin(); i != sm.end(); ++i) {
+ if (i->second.verify_error_count != 0) {
+ fprintf(stderr, "%s verify_error %llu\n", i->first.c_str(),
+ i->second.verify_error_count);
+ }
+ if (i->second.runtime_error_count) {
+ fprintf(stderr, "%s runtime_error %llu\n", i->first.c_str(),
+ i->second.runtime_error_count);
+ }
+ if (i->second.unknown_count) {
+ fprintf(stderr, "%s unknown %llu\n", i->first.c_str(),
+ i->second.unknown_count);
+ }
+ fprintf(stderr, "%s success %llu\n", i->first.c_str(),
+ i->second.success_count);
+ total.add(i->second);
+ }
+ if (total.verify_error_count != 0) {
+ fprintf(stderr, "TOTAL verify_error %llu\n", total.verify_error_count);
+ }
+ if (total.runtime_error_count != 0) {
+ fprintf(stderr, "TOTAL runtime_error %llu\n", total.runtime_error_count);
+ }
+ if (total.unknown_count != 0) {
+ fprintf(stderr, "TOTAL unknown %llu\n", total.unknown_count);
+ }
+ fprintf(stderr, "TOTAL success %llu\n", total.success_count);
+ mysql_library_end();
+ return 0;
+}
+
+};
+
+int
+main(int argc, char **argv)
+{
+ return dena::hs_longrun_main(argc, argv);
+}
+
diff --git a/plugin/handler_socket/client/hspool_test.pl b/plugin/handler_socket/client/hspool_test.pl
new file mode 100755
index 00000000..03227e31
--- /dev/null
+++ b/plugin/handler_socket/client/hspool_test.pl
@@ -0,0 +1,224 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+use DB::HandlerSocket::Pool;
+use DBI;
+
+my %conf = ();
+for my $i (@ARGV) {
+ my ($k, $v) = split(/=/, $i);
+ $conf{$k} = $v;
+}
+
+my $verbose = get_conf("verbose", 0);
+my $actions_str = get_conf("actions",
+ "create,insert,verify,verify2,verify3,verify4,clean");
+my $tablesize = get_conf("tablesize", 1000);
+my $db = get_conf("db", "hstestdb");
+my $table = get_conf("table", "testtbl");
+my $table_schema = get_conf("table_schema", undef);
+my $engine = get_conf("engine", "innodb");
+my $host = get_conf("host", "localhost");
+my $mysqlport = get_conf("mysqlport", 3306);
+my $hsport_rd = get_conf("hsport_rd", 9998);
+my $hsport_wr = get_conf("hsport_wr", 9999);
+my $loop = get_conf("loop", 10000);
+my $op = get_conf("op", "=");
+my $ssps = get_conf("ssps", 0);
+my $num_moreflds = get_conf("moreflds", 0);
+my $moreflds_prefix = get_conf("moreflds_prefix", "f");
+my $mysql_user = 'root';
+my $mysql_password = '';
+
+my $dsn = "DBI:MariaDB:database=;host=$host;port=$mysqlport"
+ . ";mariadb_server_prepare=$ssps";
+my $dbh = DBI->connect($dsn, $mysql_user, $mysql_password,
+ { RaiseError => 1 });
+my $hsargs = { 'host' => $host, 'port' => $hsport_rd };
+my $hspool = new DB::HandlerSocket::Pool({
+ hostmap => {
+ "$db.$table" => {
+ host => $host,
+ port => $hsport_rd,
+ },
+ },
+ resolve => undef,
+ error => undef,
+});
+$table_schema = "(k int primary key, fc30 varchar(30), ft text)"
+ if (!defined($table_schema));
+
+my @actions = split(/,/, $actions_str);
+for my $action (@actions) {
+ print "ACTION: $action\n";
+ eval "hstest_$action()";
+ if ($@) {
+ die $@;
+ }
+ print "ACTION: $action DONE\n";
+}
+
+sub get_conf {
+ my ($key, $def) = @_;
+ my $val = $conf{$key};
+ if ($val) {
+ print "$key=$val\n";
+ } else {
+ $val = $def;
+ my $defstr = $def || "(undef)";
+ print "$key=$defstr(default)\n";
+ }
+ return $val;
+}
+
+sub hstest_create {
+ $dbh->do("drop database if exists $db");
+ $dbh->do("create database $db");
+ $dbh->do("use $db");
+ $dbh->do("create table $table $table_schema engine=$engine");
+}
+
+sub hstest_dump {
+ $dbh->do("use $db");
+ my $sth = $dbh->prepare("select * from $table");
+ $sth->execute();
+ my $arr = $sth->fetchall_arrayref();
+ for my $rec (@$arr) {
+ print "REC:";
+ for my $row (@$rec) {
+ print " $row";
+ }
+ print "\n";
+ }
+}
+
+sub hstest_insert {
+ $dbh->do("use $db");
+ my $sth = $dbh->prepare("insert into $table values (?, ?, ?)");
+ for (my $k = 0; $k < $tablesize; ++$k) {
+ my $fc30 = "fc30_$k";
+ my $ft = "ft_$k";
+ $sth->execute($k, $fc30, $ft);
+ }
+}
+
+sub hstest_verify {
+ $dbh->do("use $db");
+ my $sth = $dbh->prepare("select * from $table order by k");
+ $sth->execute();
+ my $arr = $sth->fetchall_arrayref();
+ my $hsres = $hspool->index_find($db, $table, "PRIMARY", "k,fc30,ft",
+ ">=", [ 0 ], $tablesize, 0);
+ for (my $i = 0; $i < $tablesize; ++$i) {
+ my $rec = $arr->[$i];
+ my $differ = 0;
+ print "REC:" if $verbose;
+ for (my $j = 0; $j < 3; ++$j) {
+ my $fld = $rec->[$j];
+ my $hsidx = $i * 3 + $j;
+ my $hsfld = $hsres->[$hsidx];
+ if ($hsfld ne $fld) {
+ $differ = 1;
+ }
+ if ($differ) {
+ print " $fld:$hsfld" if $verbose;
+ } else {
+ print " $hsfld" if $verbose;
+ }
+ }
+ print "\n" if $verbose;
+ if ($differ) {
+ die "verification failed";
+ }
+ }
+}
+
+sub hstest_verify2 {
+ $dbh->do("use $db");
+ my $sth = $dbh->prepare("select * from $table order by k");
+ $sth->execute();
+ my $arr = $sth->fetchall_arrayref();
+ my $hsresa = $hspool->index_find_multi($db, $table, "PRIMARY",
+ "k,fc30,ft", [ [ -1, ">=", [ 0 ], $tablesize, 0 ] ]);
+ my $hsres = $hsresa->[0];
+ for (my $i = 0; $i < $tablesize; ++$i) {
+ my $rec = $arr->[$i];
+ my $differ = 0;
+ print "REC:" if $verbose;
+ for (my $j = 0; $j < 3; ++$j) {
+ my $fld = $rec->[$j];
+ my $hsidx = $i * 3 + $j;
+ my $hsfld = $hsres->[$hsidx];
+ if ($hsfld ne $fld) {
+ $differ = 1;
+ }
+ if ($differ) {
+ print " $fld:$hsfld" if $verbose;
+ } else {
+ print " $hsfld" if $verbose;
+ }
+ }
+ print "\n" if $verbose;
+ if ($differ) {
+ die "verification failed";
+ }
+ }
+}
+
+sub hashref_to_str {
+ my $href = $_[0];
+ my $r = '';
+ for my $k (sort keys %$href) {
+ my $v = $href->{$k};
+ $r .= "($k=>$v)";
+ }
+ return $r;
+}
+
+sub hstest_verify3 {
+ $dbh->do("use $db");
+ my $sth = $dbh->prepare("select * from $table order by k");
+ $sth->execute();
+ my $hsres_t = $hspool->index_find($db, $table, "PRIMARY", "k,fc30,ft",
+ ">=", [ 0 ], $tablesize, 0);
+ my $hsres = DB::HandlerSocket::Pool::result_single_to_hasharr(
+ [ 'k', 'fc30', 'ft' ], $hsres_t);
+ for (my $i = 0; $i < $tablesize; ++$i) {
+ my $mystr = hashref_to_str($sth->fetchrow_hashref());
+ my $hsstr = hashref_to_str($hsres->[$i]);
+ if ($mystr ne $hsstr) {
+ print "DIFF my=[$mystr] hs=[$hsstr]\n" if $verbose;
+ die "verification failed";
+ } else {
+ print "OK $hsstr\n" if $verbose;
+ }
+ }
+}
+
+sub hstest_verify4 {
+ $dbh->do("use $db");
+ my $sth = $dbh->prepare("select * from $table order by k");
+ $sth->execute();
+ my $hsres_t = $hspool->index_find($db, $table, "PRIMARY", "k,fc30,ft",
+ ">=", [ 0 ], $tablesize, 0);
+ my $hsres = DB::HandlerSocket::Pool::result_single_to_hashhash(
+ [ 'k', 'fc30', 'ft' ], 'k', $hsres_t);
+ my $rechash = $sth->fetchall_hashref('k');
+ while (my ($k, $href) = each (%$rechash)) {
+ my $mystr = hashref_to_str($href);
+ my $hsstr = hashref_to_str($hsres->{$k});
+ if ($mystr ne $hsstr) {
+ print "DIFF my=[$mystr] hs=[$hsstr]\n" if $verbose;
+ die "verification failed";
+ } else {
+ print "OK $hsstr\n" if $verbose;
+ }
+ }
+}
+
+sub hstest_clean {
+ $hspool->clear_pool();
+ $dbh->do("drop database if exists $db");
+}
+
diff --git a/plugin/handler_socket/client/hstest.cpp b/plugin/handler_socket/client/hstest.cpp
new file mode 100644
index 00000000..b5551fed
--- /dev/null
+++ b/plugin/handler_socket/client/hstest.cpp
@@ -0,0 +1,1532 @@
+
+// vim:sw=2:ai
+
+#include <signal.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <string.h>
+#include <vector>
+#include <stdlib.h>
+#include <memory>
+#include <errno.h>
+#include <mysql.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "util.hpp"
+#include "auto_ptrcontainer.hpp"
+#include "socket.hpp"
+#include "thread.hpp"
+#include "hstcpcli.hpp"
+
+#if __GNUC__ >= 4
+long atomic_exchange_and_add(volatile long *valp, long c)
+{
+ return __sync_fetch_and_add(valp, c);
+}
+#else
+#include <bits/atomicity.h>
+using namespace __gnu_cxx;
+long atomic_exchange_and_add(volatile long *valp, long c)
+{
+ return __exchange_and_add((volatile _Atomic_word *)valp, c);
+}
+#endif
+
+namespace dena {
+
+struct auto_mysql : private noncopyable {
+ auto_mysql() : db(0) {
+ reset();
+ }
+ ~auto_mysql() {
+ if (db) {
+ mysql_close(db);
+ }
+ }
+ void reset() {
+ if (db) {
+ mysql_close(db);
+ }
+ if ((db = mysql_init(0)) == 0) {
+ fatal_abort("failed to initialize mysql client");
+ }
+ }
+ operator MYSQL *() const { return db; }
+ private:
+ MYSQL *db;
+};
+
+struct auto_mysql_res : private noncopyable {
+ auto_mysql_res(MYSQL *db) {
+ res = mysql_store_result(db);
+ }
+ ~auto_mysql_res() {
+ if (res) {
+ mysql_free_result(res);
+ }
+ }
+ operator MYSQL_RES *() const { return res; }
+ private:
+ MYSQL_RES *res;
+};
+
+struct auto_mysql_stmt : private noncopyable {
+ auto_mysql_stmt(MYSQL *db) {
+ stmt = mysql_stmt_init(db);
+ }
+ ~auto_mysql_stmt() {
+ if (stmt) {
+ mysql_stmt_close(stmt);
+ }
+ }
+ operator MYSQL_STMT *() const { return stmt; }
+ private:
+ MYSQL_STMT *stmt;
+};
+
+namespace {
+
+double
+gettimeofday_double()
+{
+ struct timeval tv;
+ if (gettimeofday(&tv, 0) != 0) {
+ fatal_abort("gettimeofday");
+ }
+ return static_cast<double>(tv.tv_usec) / 1000000 + tv.tv_sec;
+}
+
+// unused
+void
+wait_close(int fd)
+{
+ char buf[1024];
+ while (true) {
+ int r = read(fd, buf, sizeof(buf));
+ if (r <= 0) {
+ break;
+ }
+ }
+}
+
+// unused
+void
+gentle_close(int fd)
+{
+ int r = shutdown(fd, SHUT_WR);
+ if (r != 0) {
+ return;
+ }
+ wait_close(fd);
+}
+
+};
+
+struct hstest_shared {
+ config conf;
+ socket_args arg;
+ int verbose;
+ size_t loop;
+ size_t pipe;
+ char op;
+ long num_threads;
+ mutable volatile long count;
+ mutable volatile long conn_count;
+ long wait_conn;
+ volatile char *keygen;
+ long keygen_size;
+ mutable volatile int enable_timing;
+ int usleep;
+ int dump;
+ hstest_shared() : verbose(0), loop(0), pipe(0), op('G'), num_threads(0),
+ count(0), conn_count(0), wait_conn(0), keygen(0), keygen_size(0),
+ enable_timing(0), usleep(0), dump(0) { }
+ void increment_count(unsigned int c = 1) const volatile {
+ atomic_exchange_and_add(&count, c);
+ }
+ void increment_conn(unsigned int c) const volatile {
+ atomic_exchange_and_add(&conn_count, c);
+ while (wait_conn != 0 && conn_count < wait_conn) {
+ sleep(1);
+ }
+ // fprintf(stderr, "wait_conn=%ld done\n", wait_conn);
+ }
+};
+
+struct hstest_thread {
+ struct arg_type {
+ size_t id;
+ const hstest_shared& sh;
+ bool watch_flag;
+ arg_type(size_t i, const hstest_shared& s, bool w)
+ : id(i), sh(s), watch_flag(w) { }
+ };
+ hstest_thread(const arg_type& a) : arg(a), io_success_count(0),
+ op_success_count(0), response_min(99999), response_max(0),
+ response_sum(0), response_avg(0) { }
+ void operator ()();
+ void test_1();
+ void test_2_3(int test_num);
+ void test_4_5(int test_num);
+ void test_6(int test_num);
+ void test_7(int test_num);
+ void test_8(int test_num);
+ void test_9(int test_num);
+ void test_10(int test_num);
+ void test_11(int test_num);
+ void test_12(int test_num);
+ void test_21(int test_num);
+ void test_22(int test_num);
+ void test_watch();
+ void sleep_if();
+ void set_timing(double time_spent);
+ arg_type arg;
+ auto_file fd;
+ size_t io_success_count;
+ size_t op_success_count;
+ double response_min, response_max, response_sum, response_avg;
+};
+
+void
+hstest_thread::test_1()
+{
+ char buf[1024];
+ unsigned int seed = arg.id;
+ seed ^= arg.sh.conf.get_int("seed_xor", 0);
+ std::string err;
+ if (socket_connect(fd, arg.sh.arg, err) != 0) {
+ fprintf(stderr, "connect: %d %s\n", errno, strerror(errno));
+ return;
+ }
+ const char op = arg.sh.op;
+ const int tablesize = arg.sh.conf.get_int("tablesize", 0);
+ for (size_t i = 0; i < arg.sh.loop; ++i) {
+ for (size_t j = 0; j < arg.sh.pipe; ++j) {
+ int k = 0, v = 0, len = 0;
+ if (op == 'G') {
+ k = rand_r(&seed);
+ v = rand_r(&seed); /* unused */
+ if (tablesize != 0) {
+ k &= tablesize;
+ }
+ len = snprintf(buf, sizeof(buf), "%c\tk%d\n", op, k);
+ } else {
+ k = rand_r(&seed);
+ v = rand_r(&seed);
+ if (tablesize != 0) {
+ k &= tablesize;
+ }
+ len = snprintf(buf, sizeof(buf), "%c\tk%d\tv%d\n", op, k, v);
+ }
+ const int wlen = write(fd.get(), buf, len);
+ if (wlen != len) {
+ return;
+ }
+ }
+ size_t read_cnt = 0;
+ size_t read_pos = 0;
+ while (read_cnt < arg.sh.pipe) {
+ const int rlen = read(fd.get(), buf + read_pos, sizeof(buf) - read_pos);
+ if (rlen <= 0) {
+ return;
+ }
+ read_pos += rlen;
+ while (true) {
+ const char *const p = static_cast<const char *>(memchr(buf, '\n',
+ read_pos));
+ if (p == 0) {
+ break;
+ }
+ ++read_cnt;
+ ++io_success_count;
+ arg.sh.increment_count();
+ if (p != buf && buf[0] == '=') {
+ ++op_success_count;
+ }
+ const size_t rest_size = buf + read_pos - (p + 1);
+ if (rest_size != 0) {
+ memmove(buf, p + 1, rest_size);
+ }
+ read_pos = rest_size;
+ }
+ }
+ }
+}
+
+void
+hstest_thread::test_2_3(int test_num)
+{
+#if 0
+ char buf_k[128], buf_v[128];
+ unsigned int seed = arg.id;
+ op_base_t op = static_cast<op_base_t>(arg.sh.op);
+ micli_ptr hnd;
+ if (test_num == 2) {
+ hnd = micli_i::create_remote(arg.sh.conf);
+ } else if (test_num == 3) {
+ // hnd = micli_i::create_inproc(arg.sh.localdb);
+ }
+ if (hnd.get() == 0) {
+ return;
+ }
+ for (size_t i = 0; i < arg.sh.loop; ++i) {
+ for (size_t j = 0; j < arg.sh.pipe; ++j) {
+ int k = 0, v = 0, klen = 0, vlen = 0;
+ k = rand_r(&seed);
+ klen = snprintf(buf_k, sizeof(buf_k), "k%d", k);
+ v = rand_r(&seed); /* unused */
+ vlen = snprintf(buf_v, sizeof(buf_v), "v%d", v);
+ string_ref arr[2];
+ arr[0] = string_ref(buf_k, klen);
+ arr[1] = string_ref(buf_v, vlen);
+ pstrarr_ptr rec(arr, 2);
+ if (hnd->execute(op, 0, 0, rec.get_const())) {
+ ++io_success_count;
+ arg.sh.increment_count();
+ const dataset& res = hnd->get_result_ref();
+ if (res.size() == 1) {
+ ++op_success_count;
+ }
+ }
+ }
+ }
+#endif
+}
+
+void
+hstest_thread::test_4_5(int test_num)
+{
+#if 0
+ char buf_k[128], buf_v[8192];
+ memset(buf_v, ' ', sizeof(buf_v));
+ unsigned int seed = arg.id;
+ op_base_t op = static_cast<op_base_t>(arg.sh.op);
+ micli_ptr hnd;
+ if (test_num == 4) {
+ hnd = micli_i::create_remote(arg.sh.conf);
+ } else if (test_num == 5) {
+ hnd = micli_i::create_inproc(arg.sh.localdb);
+ }
+ if (hnd.get() == 0) {
+ return;
+ }
+ for (size_t i = 0; i < arg.sh.loop; ++i) {
+ for (size_t j = 0; j < arg.sh.pipe; ++j) {
+ int k = 0, klen = 0, vlen = 0;
+ k = i & 0x0000ffffUL;
+ if (k == 0) {
+ fprintf(stderr, "k=0\n");
+ }
+ klen = snprintf(buf_k, sizeof(buf_k), "k%d", k);
+ vlen = rand_r(&seed) % 8192;
+ string_ref arr[2];
+ arr[0] = string_ref(buf_k, klen);
+ arr[1] = string_ref(buf_v, vlen);
+ pstrarr_ptr rec(arr, 2);
+ if (hnd->execute(op, 0, 0, rec.get_const())) {
+ ++io_success_count;
+ const dataset& res = hnd->get_result_ref();
+ if (res.size() == 1) {
+ ++op_success_count;
+ }
+ }
+ }
+ }
+#endif
+}
+
+void
+hstest_thread::test_6(int test_num)
+{
+ int count = arg.sh.conf.get_int("count", 1);
+ auto_file fds[count];
+ for (int i = 0; i < count; ++i) {
+ const double t1 = gettimeofday_double();
+ std::string err;
+ if (socket_connect(fds[i], arg.sh.arg, err) != 0) {
+ fprintf(stderr, "id=%zu i=%d err=%s\n", arg.id, i, err.c_str());
+ }
+ const double t2 = gettimeofday_double();
+ if (t2 - t1 > 1) {
+ fprintf(stderr, "id=%zu i=%d time %f\n", arg.id, i, t2 - t1);
+ }
+ }
+}
+
+void
+hstest_thread::test_7(int num)
+{
+ /*
+ set foo 0 0 10
+ 0123456789
+ STORED
+ get foo
+ VALUE foo 0 10
+ 0123456789
+ END
+ get var
+ END
+ */
+ char buf[1024];
+ const int keep_connection = arg.sh.conf.get_int("keep_connection", 1);
+ unsigned int seed = arg.id;
+ seed ^= arg.sh.conf.get_int("seed_xor", 0);
+ const int tablesize = arg.sh.conf.get_int("tablesize", 0);
+ const char op = arg.sh.op;
+ for (size_t i = 0; i < arg.sh.loop; ++i) {
+ const double tm1 = gettimeofday_double();
+ std::string err;
+ if (fd.get() < 0 && socket_connect(fd, arg.sh.arg, err) != 0) {
+ fprintf(stderr, "connect: %d %s\n", errno, strerror(errno));
+ return;
+ }
+ for (size_t j = 0; j < arg.sh.pipe; ++j) {
+ int k = 0, v = 0, len = 0;
+ if (op == 'G') {
+ k = rand_r(&seed);
+ v = rand_r(&seed); /* unused */
+ if (tablesize != 0) {
+ k &= tablesize;
+ }
+ len = snprintf(buf, sizeof(buf), "get k%d\r\n", k);
+ } else {
+ k = rand_r(&seed);
+ v = rand_r(&seed);
+ if (tablesize != 0) {
+ k &= tablesize;
+ }
+ char vbuf[1024];
+ int vlen = snprintf(vbuf, sizeof(vbuf),
+ "v%d"
+ // "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ // "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ // "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ // "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ // "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ , v);
+ len = snprintf(buf, sizeof(buf), "set k%d 0 0 %d\r\n%s\r\n",
+ k, vlen, vbuf);
+ }
+ const int wlen = write(fd.get(), buf, len);
+ if (wlen != len) {
+ return;
+ }
+ }
+ size_t read_cnt = 0;
+ size_t read_pos = 0;
+ bool read_response_done = false;
+ bool expect_value = false;
+ while (!read_response_done) {
+ const int rlen = read(fd.get(), buf + read_pos, sizeof(buf) - read_pos);
+ if (rlen <= 0) {
+ return;
+ }
+ read_pos += rlen;
+ while (true) {
+ const char *const p = static_cast<const char *>(memchr(buf, '\n',
+ read_pos));
+ if (p == 0) {
+ break;
+ }
+ ++read_cnt;
+ if (expect_value) {
+ expect_value = false;
+ } else if (p >= buf + 6 && memcmp(buf, "VALUE ", 6) == 0) {
+ expect_value = true;
+ ++op_success_count;
+ } else {
+ if (p == buf + 7 && memcmp(buf, "STORED\r", 7) == 0) {
+ ++op_success_count;
+ }
+ read_response_done = true;
+ }
+ const size_t rest_size = buf + read_pos - (p + 1);
+ if (rest_size != 0) {
+ memmove(buf, p + 1, rest_size);
+ }
+ read_pos = rest_size;
+ }
+ ++io_success_count;
+ }
+ arg.sh.increment_count();
+ if (!keep_connection) {
+ fd.close();
+ }
+ const double tm2 = gettimeofday_double();
+ set_timing(tm2 - tm1);
+ sleep_if();
+ }
+}
+
+struct rec {
+ std::string key;
+ std::string value;
+};
+
+void
+hstest_thread::test_8(int test_num)
+{
+#if 0
+ char buf_k[128], buf_v[128];
+ unsigned int seed = arg.id;
+ // op_base_t op = static_cast<op_base_t>(arg.sh.op);
+ using namespace boost::multi_index;
+ typedef member<rec, std::string, &rec::key> rec_get_key;
+ typedef ordered_unique<rec_get_key> oui;
+ typedef multi_index_container< rec, indexed_by<oui> > mic;
+ #if 0
+ typedef std::map<std::string, std::string> m_type;
+ m_type m;
+ #endif
+ mic m;
+ for (size_t i = 0; i < arg.sh.loop; ++i) {
+ for (size_t j = 0; j < arg.sh.pipe; ++j) {
+ int k = 0, v = 0, klen = 0, vlen = 0;
+ k = rand_r(&seed);
+ klen = snprintf(buf_k, sizeof(buf_k), "k%d", k);
+ v = rand_r(&seed); /* unused */
+ vlen = snprintf(buf_v, sizeof(buf_v), "v%d", v);
+ const std::string ks(buf_k, klen);
+ const std::string vs(buf_v, vlen);
+ rec r;
+ r.key = ks;
+ r.value = vs;
+ m.insert(r);
+ // m.insert(std::make_pair(ks, vs));
+ ++io_success_count;
+ ++op_success_count;
+ arg.sh.increment_count();
+ }
+ }
+#endif
+}
+
+struct mysqltest_thread_initobj : private noncopyable {
+ mysqltest_thread_initobj() {
+ mysql_thread_init();
+ }
+ ~mysqltest_thread_initobj() {
+ mysql_thread_end();
+ }
+};
+
+void
+hstest_thread::test_9(int test_num)
+{
+ /* create table hstest
+ * ( k varchar(255) not null, v varchar(255) not null, primary key(k))
+ * engine = innodb; */
+ auto_mysql db;
+ // mysqltest_thread_initobj initobj;
+ std::string err;
+ const char op = arg.sh.op;
+ const std::string suffix = arg.sh.conf.get_str("value_suffix", "upd");
+ unsigned long long err_cnt = 0;
+ unsigned long long query_cnt = 0;
+ #if 0
+ my_bool reconnect = 0;
+ if (mysql_options(db, MYSQL_OPT_RECONNECT, &reconnect) != 0) {
+ err = "mysql_options() failed";
+ ++err_cnt;
+ return;
+ }
+ #endif
+ unsigned int seed = time(0) + arg.id + 1;
+ seed ^= arg.sh.conf.get_int("seed_xor", 0);
+ drand48_data randbuf;
+ srand48_r(seed, &randbuf);
+ const std::string mysql_host = arg.sh.conf.get_str("host", "localhost");
+ const int mysql_port = arg.sh.conf.get_int("mysqlport", 3306);
+ const int num = arg.sh.loop;
+ const std::string mysql_user = arg.sh.conf.get_str("mysqluser", "root");
+ const std::string mysql_passwd = arg.sh.conf.get_str("mysqlpass", "");
+ const std::string mysql_dbname = arg.sh.conf.get_str("dbname", "hstest");
+ const int keep_connection = arg.sh.conf.get_int("keep_connection", 1);
+ const int verbose = arg.sh.conf.get_int("verbose", 1);
+ const int tablesize = arg.sh.conf.get_int("tablesize", 10000);
+ const int moreflds = arg.sh.conf.get_int("moreflds", 0);
+ const std::string moreflds_prefix = arg.sh.conf.get_str(
+ "moreflds_prefix", "column0123456789_");
+ const int use_handler = arg.sh.conf.get_int("handler", 0);
+ const int sched_flag = arg.sh.conf.get_int("sched", 0);
+ const int use_in = arg.sh.conf.get_int("in", 0);
+ const int ssps = use_in ? 0 : arg.sh.conf.get_int("ssps", 0);
+ std::string flds = "v";
+ for (int i = 0; i < moreflds; ++i) {
+ char buf[1024];
+ snprintf(buf, sizeof(buf), ",%s%d", moreflds_prefix.c_str(), i);
+ flds += std::string(buf);
+ }
+ int connected = 0;
+ std::auto_ptr<auto_mysql_stmt> stmt;
+ string_buffer wbuf;
+ for (int i = 0; i < num; ++i) {
+ const double tm1 = gettimeofday_double();
+ const int flags = 0;
+ if (connected == 0) {
+ if (!mysql_real_connect(db, mysql_host.c_str(),
+ mysql_user.c_str(), mysql_user.empty() ? 0 : mysql_passwd.c_str(),
+ mysql_dbname.c_str(), mysql_port, 0, flags)) {
+ err = "failed to connect: " + std::string(mysql_error(db));
+ if (verbose >= 1) {
+ fprintf(stderr, "e=[%s]\n", err.c_str());
+ }
+ ++err_cnt;
+ return;
+ }
+ arg.sh.increment_conn(1);
+ }
+ int r = 0;
+ if (connected == 0 && use_handler) {
+ const char *const q = "handler hstest_table1 open";
+ r = mysql_real_query(db, q, strlen(q));
+ if (r != 0) {
+ err = 1;
+ }
+ }
+ if (connected == 0 && ssps) {
+ stmt.reset(new auto_mysql_stmt(db));
+ const char *const q = "select v from hstest_table1 where k = ?";
+ r = mysql_stmt_prepare(*stmt, q, strlen(q));
+ if (r != 0) {
+ fprintf(stderr, "ssps err\n");
+ ++err_cnt;
+ return;
+ }
+ }
+ connected = 1;
+ std::string result_str;
+ unsigned int err = 0;
+ unsigned int num_flds = 0, num_affected_rows = 0;
+ int got_data = 0;
+ char buf_query[16384];
+ int buf_query_len = 0;
+ int k = 0, v = 0;
+ {
+ double kf = 0, vf = 0;
+ drand48_r(&randbuf, &kf);
+ drand48_r(&randbuf, &vf);
+ k = int(kf * tablesize);
+ v = int(vf * tablesize);
+ #if 0
+ k = rand_r(&seed);
+ v = rand_r(&seed);
+ if (tablesize != 0) {
+ k %= tablesize;
+ }
+ #endif
+ if (op == 'G') {
+ if (use_handler) {
+ buf_query_len = snprintf(buf_query, sizeof(buf_query),
+ "handler hstest_table1 read `primary` = ( '%d' )", k);
+ // TODO: moreflds
+ } else if (ssps) {
+ //
+ } else if (use_in) {
+ wbuf.clear();
+ char *p = wbuf.make_space(1024);
+ int len = snprintf(p, 1024, "select %s from hstest_table1 where k in ('%d'", flds.c_str(), k);
+ wbuf.space_wrote(len);
+ for (int j = 1; j < use_in; ++j) {
+ /* generate more key */
+ drand48_r(&randbuf, &kf);
+ k = int(kf * tablesize);
+ p = wbuf.make_space(1024);
+ int len = snprintf(p, 1024, ", '%d'", k);
+ wbuf.space_wrote(len);
+ }
+ wbuf.append_literal(")");
+ } else {
+ buf_query_len = snprintf(buf_query, sizeof(buf_query),
+ "select %s from hstest_table1 where k = '%d'", flds.c_str(), k);
+ }
+ } else if (op == 'U') {
+ buf_query_len = snprintf(buf_query, sizeof(buf_query),
+ "update hstest_table1 set v = '%d_%d%s' where k = '%d'",
+ v, k, suffix.c_str(), k);
+ } else if (op == 'R') {
+ buf_query_len = snprintf(buf_query, sizeof(buf_query),
+ "replace into hstest_table1 values ('%d', 'v%d')", k, v);
+ // TODO: moreflds
+ }
+ }
+ if (r == 0) {
+ if (ssps) {
+ MYSQL_BIND bind[1] = { };
+ bind[0].buffer_type = MYSQL_TYPE_LONG;
+ bind[0].buffer = (char *)&k;
+ bind[0].is_null = 0;
+ bind[0].length = 0;
+ if (mysql_stmt_bind_param(*stmt, bind)) {
+ fprintf(stderr, "err: %s\n", mysql_stmt_error(*stmt));
+ ++err_cnt;
+ return;
+ }
+ r = mysql_stmt_execute(*stmt);
+ // fprintf(stderr, "stmt exec\n");
+ } else if (use_in) {
+ r = mysql_real_query(db, wbuf.begin(), wbuf.size());
+ } else {
+ r = mysql_real_query(db, buf_query, buf_query_len);
+ // fprintf(stderr, "real query\n");
+ }
+ ++query_cnt;
+ }
+ if (r != 0) {
+ err = 1;
+ } else if (ssps) {
+ if (verbose >= 0) {
+ char resbuf[1024];
+ unsigned long res_len = 0;
+ MYSQL_BIND bind[1] = { };
+ bind[0].buffer_type = MYSQL_TYPE_STRING;
+ bind[0].buffer = resbuf;
+ bind[0].buffer_length = sizeof(resbuf);
+ bind[0].length = &res_len;
+ if (mysql_stmt_bind_result(*stmt, bind)) {
+ fprintf(stderr, "err: %s\n", mysql_stmt_error(*stmt));
+ ++err_cnt;
+ return;
+ }
+ if (mysql_stmt_fetch(*stmt)) {
+ fprintf(stderr, "err: %s\n", mysql_stmt_error(*stmt));
+ ++err_cnt;
+ return;
+ }
+ if (!result_str.empty()) {
+ result_str += " ";
+ }
+ result_str += std::string(resbuf, res_len);
+ // fprintf(stderr, "SSPS RES: %s\n", result_str.c_str());
+ got_data = 1;
+ } else {
+ got_data = 1;
+ }
+ } else {
+ auto_mysql_res res(db);
+ if (res != 0) {
+ if (verbose >= 0) {
+ num_flds = mysql_num_fields(res);
+ MYSQL_ROW row = 0;
+ while ((row = mysql_fetch_row(res)) != 0) {
+ got_data += 1;
+ unsigned long *const lengths = mysql_fetch_lengths(res);
+ if (verbose >= 2) {
+ for (unsigned int i = 0; i < num_flds; ++i) {
+ if (!result_str.empty()) {
+ result_str += " ";
+ }
+ result_str += std::string(row[i], lengths[i]);
+ }
+ }
+ }
+ } else {
+ MYSQL_ROW row = 0;
+ while ((row = mysql_fetch_row(res)) != 0) {
+ got_data += 1;
+ }
+ }
+ } else {
+ if (mysql_field_count(db) == 0) {
+ num_affected_rows = mysql_affected_rows(db);
+ } else {
+ err = 1;
+ }
+ }
+ }
+ if (verbose >= 2 || (verbose >= 1 && err != 0)) {
+ if (err) {
+ ++err_cnt;
+ const char *const errstr = mysql_error(db);
+ fprintf(stderr, "e=[%s] a=%u q=[%s]\n", errstr,
+ num_affected_rows, buf_query);
+ } else {
+ fprintf(stderr, "a=%u q=[%s] r=[%s]\n", num_affected_rows, buf_query,
+ result_str.c_str());
+ }
+ }
+ if (err == 0) {
+ ++io_success_count;
+ if (num_affected_rows > 0 || got_data > 0) {
+ op_success_count += got_data;
+ } else {
+ if (verbose >= 1) {
+ fprintf(stderr, "k=%d numaff=%u gotdata=%d\n",
+ k, num_affected_rows, got_data);
+ }
+ }
+ arg.sh.increment_count();
+ }
+ if (!keep_connection) {
+ if (stmt.get() != 0) {
+ stmt.reset();
+ }
+ db.reset();
+ connected = 0;
+ }
+ const double tm2 = gettimeofday_double();
+ set_timing(tm2 - tm1);
+ sleep_if();
+ if (sched_flag) {
+ sched_yield();
+ }
+ }
+ if (verbose >= 1) {
+ fprintf(stderr, "thread finished (error_count=%llu)\n", err_cnt);
+ }
+}
+
+void
+hstest_thread::test_10(int test_num)
+{
+ const int keep_connection = arg.sh.conf.get_int("keep_connection", 1);
+ unsigned int seed = time(0) + arg.id + 1;
+ seed ^= arg.sh.conf.get_int("seed_xor", 0);
+ drand48_data randbuf;
+ srand48_r(seed, &randbuf);
+ std::string err;
+ int keepconn_count = 0;
+ const char op = arg.sh.op;
+ const int verbose = arg.sh.conf.get_int("verbose", 1);
+ const std::string suffix = arg.sh.conf.get_str("value_suffix", "upd");
+ const int tablesize = arg.sh.conf.get_int("tablesize", 10000);
+ const int firstkey = arg.sh.conf.get_int("firstkey", 0);
+ const int sched_flag = arg.sh.conf.get_int("sched", 0);
+ const int moreflds = arg.sh.conf.get_int("moreflds", 0);
+ const std::string dbname = arg.sh.conf.get_str("dbname", "hstest");
+ const std::string table = arg.sh.conf.get_str("table", "hstest_table1");
+ const std::string index = arg.sh.conf.get_str("index", "PRIMARY");
+ const std::string field = arg.sh.conf.get_str("field", "v");
+ const int use_in = arg.sh.conf.get_int("in", 0);
+ const std::string moreflds_prefix = arg.sh.conf.get_str(
+ "moreflds_prefix", "column0123456789_");
+ const int dump = arg.sh.dump;
+ const int nodup = arg.sh.conf.get_int("nodup", 0);
+ std::string moreflds_str;
+ for (int i = 0; i < moreflds; ++i) {
+ char sbuf[1024];
+ snprintf(sbuf, sizeof(sbuf), ",%s%d", moreflds_prefix.c_str(), i);
+ moreflds_str += std::string(sbuf);
+ }
+ string_buffer wbuf;
+ char rbuf[16384];
+ for (size_t i = 0; i < arg.sh.loop; ++i) {
+ int len = 0, rlen = 0, wlen = 0;
+ #if 0
+ const double tm1 = gettimeofday_double();
+ #endif
+ if (fd.get() < 0) {
+ if (socket_connect(fd, arg.sh.arg, err) != 0) {
+ fprintf(stderr, "connect: %d %s\n", errno, strerror(errno));
+ return;
+ }
+ char *wp = wbuf.make_space(1024);
+ len = snprintf(wp, 1024,
+ "P\t1\t%s\t%s\tPRIMARY\t%s%s\n", dbname.c_str(), table.c_str(),
+ field.c_str(), moreflds_str.c_str());
+ /* pst_num, db, table, index, retflds */
+ wbuf.space_wrote(len);
+ wlen = write(fd.get(), wbuf.begin(), len);
+ if (len != wlen) {
+ fprintf(stderr, "write: %d %d\n", len, wlen);
+ return;
+ }
+ wbuf.clear();
+ rlen = read(fd.get(), rbuf, sizeof(rbuf));
+ if (rlen <= 0 || rbuf[rlen - 1] != '\n') {
+ fprintf(stderr, "read: rlen=%d errno=%d\n", rlen, errno);
+ return;
+ }
+ if (rbuf[0] != '0') {
+ fprintf(stderr, "failed to open table\n");
+ return;
+ }
+ arg.sh.increment_conn(1);
+ }
+ const double tm1 = gettimeofday_double();
+ for (size_t j = 0; j < arg.sh.pipe; ++j) {
+ int k = 0, v = 0;
+ {
+ while (true) {
+ double kf = 0, vf = 0;
+ drand48_r(&randbuf, &kf);
+ drand48_r(&randbuf, &vf);
+ k = int(kf * tablesize) + firstkey;
+ v = int(vf * tablesize) + firstkey;
+ if (k - firstkey < arg.sh.keygen_size) {
+ volatile char *const ptr = arg.sh.keygen + (k - firstkey);
+ // int oldv = __sync_fetch_and_or(ptr, 1);
+ int oldv = *ptr;
+ *ptr += 1;
+ if (nodup && oldv != 0) {
+ if (dump) {
+ fprintf(stderr, "retry\n");
+ }
+ continue;
+ }
+ } else {
+ if (nodup) {
+ if (dump) {
+ fprintf(stderr, "retry2\n");
+ }
+ continue;
+ }
+ }
+ size_t len = 0;
+ if (op == 'G') {
+ if (use_in) {
+ char *wp = wbuf.make_space(1024);
+ len = snprintf(wp, 1024, "1\t=\t1\t\t%d\t0\t@\t0\t%d\t%d",
+ use_in, use_in, k);
+ wbuf.space_wrote(len);
+ for (int j = 1; j < use_in; ++j) {
+ drand48_r(&randbuf, &kf);
+ k = int(kf * tablesize) + firstkey;
+ char *wp = wbuf.make_space(1024);
+ len = snprintf(wp, 1024, "\t%d", k);
+ wbuf.space_wrote(len);
+ }
+ wbuf.append_literal("\n");
+ } else {
+ char *wp = wbuf.make_space(1024);
+ len = snprintf(wp, 1024, "1\t=\t1\t%d\n", k);
+ wbuf.space_wrote(len);
+ }
+ } else if (op == 'U') {
+ char *wp = wbuf.make_space(1024);
+ len = snprintf(wp, 1024,
+ "1\t=\t1\t%d\t1\t0\tU\t%d_%d%s\n", k, v, k, suffix.c_str());
+ wbuf.space_wrote(len);
+ }
+ break;
+ }
+ }
+ }
+ wlen = write(fd.get(), wbuf.begin(), wbuf.size());
+ if ((size_t) wlen != wbuf.size()) {
+ fprintf(stderr, "write: %d %d\n", (int)wbuf.size(), wlen);
+ return;
+ }
+ wbuf.clear();
+ size_t read_cnt = 0;
+ size_t read_pos = 0;
+ while (read_cnt < arg.sh.pipe) {
+ rlen = read(fd.get(), rbuf + read_pos, sizeof(rbuf) - read_pos);
+ if (rlen <= 0) {
+ fprintf(stderr, "read: %d\n", rlen);
+ return;
+ }
+ read_pos += rlen;
+ while (true) {
+ const char *const nl = static_cast<const char *>(memchr(rbuf, '\n',
+ read_pos));
+ if (nl == 0) {
+ break;
+ }
+ ++read_cnt;
+ ++io_success_count;
+ const char *t1 = static_cast<const char *>(memchr(rbuf, '\t',
+ nl - rbuf));
+ if (t1 == 0) {
+ fprintf(stderr, "error \n");
+ break;
+ }
+ ++t1;
+ const char *t2 = static_cast<const char *>(memchr(t1, '\t',
+ nl - t1));
+ if (t2 == 0) {
+ if (verbose > 1) {
+ fprintf(stderr, "key: notfound \n");
+ }
+ break;
+ }
+ ++t2;
+ if (t1 == rbuf + 2 && rbuf[0] == '0') {
+ if (op == 'G') {
+ ++op_success_count;
+ arg.sh.increment_count();
+ } else if (op == 'U') {
+ const char *t3 = t2;
+ while (t3 != nl && t3[0] >= 0x10) {
+ ++t3;
+ }
+ if (t3 != t2 + 1 || t2[0] != '1') {
+ const std::string mess(t2, t3);
+ fprintf(stderr, "mod: %s\n", mess.c_str());
+ } else {
+ ++op_success_count;
+ arg.sh.increment_count();
+ if (arg.sh.dump && arg.sh.pipe == 1) {
+ fwrite(wbuf.begin(), wbuf.size(), 1, stderr);
+ }
+ }
+ }
+ } else {
+ const char *t3 = t2;
+ while (t3 != nl && t3[0] >= 0x10) {
+ ++t3;
+ }
+ const std::string mess(t2, t3);
+ fprintf(stderr, "err: %s\n", mess.c_str());
+ }
+ const size_t rest_size = rbuf + read_pos - (nl + 1);
+ if (rest_size != 0) {
+ memmove(rbuf, nl + 1, rest_size);
+ }
+ read_pos = rest_size;
+ }
+ }
+ if (!keep_connection) {
+ fd.reset();
+ arg.sh.increment_conn(-1);
+ } else if (keep_connection > 1 && ++keepconn_count > keep_connection) {
+ keepconn_count = 0;
+ fd.reset();
+ arg.sh.increment_conn(-1);
+ }
+ const double tm2 = gettimeofday_double();
+ set_timing(tm2 - tm1);
+ sleep_if();
+ if (sched_flag) {
+ sched_yield();
+ }
+ }
+ if (dump) {
+ fprintf(stderr, "done\n");
+ }
+}
+
+void
+hstest_thread::sleep_if()
+{
+ if (arg.sh.usleep) {
+ struct timespec ts = {
+ arg.sh.usleep / 1000000,
+ (arg.sh.usleep % 1000000) * 1000
+ };
+ nanosleep(&ts, 0);
+ }
+}
+
+void
+hstest_thread::set_timing(double time_spent)
+{
+ response_min = std::min(response_min, time_spent);
+ response_max = std::max(response_max, time_spent);
+ response_sum += time_spent;
+ if (op_success_count != 0) {
+ response_avg = response_sum / op_success_count;
+ }
+}
+
+void
+hstest_thread::test_11(int test_num)
+{
+ const int keep_connection = arg.sh.conf.get_int("keep_connection", 1);
+ const int tablesize = arg.sh.conf.get_int("tablesize", 0);
+ unsigned int seed = arg.id;
+ seed ^= arg.sh.conf.get_int("seed_xor", 0);
+ std::string err;
+ hstcpcli_ptr cli;
+ for (size_t i = 0; i < arg.sh.loop; ++i) {
+ if (cli.get() == 0) {
+ cli = hstcpcli_i::create(arg.sh.arg);
+ cli->request_buf_open_index(0, "hstest", "hstest_table1", "", "v");
+ /* pst_num, db, table, index, retflds */
+ if (cli->request_send() != 0) {
+ fprintf(stderr, "reuqest_send: %s\n", cli->get_error().c_str());
+ return;
+ }
+ size_t num_flds = 0;
+ if (cli->response_recv(num_flds) != 0) {
+ fprintf(stderr, "reuqest_recv: %s\n", cli->get_error().c_str());
+ return;
+ }
+ cli->response_buf_remove();
+ }
+ for (size_t j = 0; j < arg.sh.pipe; ++j) {
+ char buf[256];
+ int k = 0, v = 0, len = 0;
+ {
+ k = rand_r(&seed);
+ v = rand_r(&seed); /* unused */
+ if (tablesize != 0) {
+ k &= tablesize;
+ }
+ len = snprintf(buf, sizeof(buf), "%d", k);
+ }
+ const string_ref key(buf, len);
+ const string_ref op("=", 1);
+ cli->request_buf_exec_generic(0, op, &key, 1, 1, 0, string_ref(), 0, 0);
+ }
+ if (cli->request_send() != 0) {
+ fprintf(stderr, "reuqest_send: %s\n", cli->get_error().c_str());
+ return;
+ }
+ size_t read_cnt = 0;
+ for (size_t j = 0; j < arg.sh.pipe; ++j) {
+ size_t num_flds = 0;
+ if (cli->response_recv(num_flds) != 0) {
+ fprintf(stderr, "reuqest_recv: %s\n", cli->get_error().c_str());
+ return;
+ }
+ {
+ ++read_cnt;
+ ++io_success_count;
+ arg.sh.increment_count();
+ {
+ ++op_success_count;
+ }
+ }
+ cli->response_buf_remove();
+ }
+ if (!keep_connection) {
+ cli.reset();
+ }
+ }
+}
+
+void
+hstest_thread::test_watch()
+{
+ const int timelimit = arg.sh.conf.get_int("timelimit", 0);
+ const int timelimit_offset = timelimit / 2;
+ int loop = 0;
+ double t1 = 0, t2 = 0;
+ size_t cnt_t1 = 0, cnt_t2 = 0;
+ size_t prev_cnt = 0;
+ double now_f = 0;
+ while (true) {
+ sleep(1);
+ const size_t cnt = arg.sh.count;
+ const size_t df = cnt - prev_cnt;
+ prev_cnt = cnt;
+ const double now_prev = now_f;
+ now_f = gettimeofday_double();
+ if (now_prev != 0) {
+ const double rps = static_cast<double>(df) / (now_f - now_prev);
+ fprintf(stderr, "now: %zu cntdiff: %zu tdiff: %f rps: %f\n",
+ static_cast<size_t>(now_f), df, now_f - now_prev, rps);
+ }
+ if (timelimit != 0) {
+ if (arg.sh.wait_conn == 0 || arg.sh.conn_count >= arg.sh.wait_conn) {
+ ++loop;
+ }
+ if (loop == timelimit_offset) {
+ t1 = gettimeofday_double();
+ cnt_t1 = cnt;
+ arg.sh.enable_timing = 1;
+ fprintf(stderr, "start timing\n");
+ } else if (loop == timelimit_offset + timelimit) {
+ t2 = gettimeofday_double();
+ cnt_t2 = cnt;
+ const size_t cnt_diff = cnt_t2 - cnt_t1;
+ const double tdiff = t2 - t1;
+ const double qps = cnt_diff / (tdiff != 0 ? tdiff : 1);
+ fprintf(stderr, "(%f: %zu, %f: %zu), %10.5f qps\n",
+ t1, cnt_t1, t2, cnt_t2, qps);
+ size_t keycnt = 0;
+ for (int i = 0; i < arg.sh.keygen_size; ++i) {
+ if (arg.sh.keygen[i]) {
+ ++keycnt;
+ }
+ }
+ fprintf(stderr, "keygen=%zu\n", keycnt);
+ break;
+ }
+ }
+ }
+#if 0
+ int loop = 0;
+ double t1 = 0, t2 = 0;
+ size_t cnt_t1 = 0, cnt_t2 = 0;
+ size_t prev_cnt = 0;
+ while (true) {
+ sleep(1);
+ const size_t cnt = arg.sh.count;
+ const size_t df = cnt - prev_cnt;
+ prev_cnt = cnt;
+ const size_t now = time(0);
+ fprintf(stderr, "%zu %zu\n", now, df);
+ if (timelimit != 0) {
+ ++loop;
+ if (loop == timelimit_offset) {
+ t1 = gettimeofday_double();
+ cnt_t1 = cnt;
+ } else if (loop == timelimit_offset + timelimit) {
+ t2 = gettimeofday_double();
+ cnt_t2 = cnt;
+ const size_t cnt_diff = cnt_t2 - cnt_t1;
+ const double tdiff = t2 - t1;
+ const double qps = cnt_diff / (tdiff != 0 ? tdiff : 1);
+ fprintf(stderr, "(%f: %zu, %f: %zu), %10.5f qps\n",
+ t1, cnt_t1, t2, cnt_t2, qps);
+ size_t keycnt = 0;
+ for (int i = 0; i < arg.sh.keygen_size; ++i) {
+ if (arg.sh.keygen[i]) {
+ ++keycnt;
+ }
+ }
+ fprintf(stderr, "keygen=%zu\n", keycnt);
+ _exit(0);
+ }
+ }
+ }
+#endif
+}
+
+void
+hstest_thread::test_12(int test_num)
+{
+ /* NOTE: num_threads should be 1 */
+ /* create table hstest
+ * ( k varchar(255) not null, v varchar(255) not null, primary key(k))
+ * engine = innodb; */
+ mysqltest_thread_initobj initobj;
+ auto_mysql db;
+ std::string err;
+ unsigned long long err_cnt = 0;
+ unsigned long long query_cnt = 0;
+ #if 0
+ my_bool reconnect = 0;
+ if (mysql_options(db, MYSQL_OPT_RECONNECT, &reconnect) != 0) {
+ err = "mysql_options() failed";
+ ++err_cnt;
+ return;
+ }
+ #endif
+ const std::string mysql_host = arg.sh.conf.get_str("host", "localhost");
+ const int mysql_port = arg.sh.conf.get_int("mysqlport", 3306);
+ const unsigned int num = arg.sh.loop;
+ const size_t pipe = arg.sh.pipe;
+ const std::string mysql_user = arg.sh.conf.get_str("mysqluser", "root");
+ const std::string mysql_passwd = arg.sh.conf.get_str("mysqlpass", "");
+ const std::string mysql_dbname = arg.sh.conf.get_str("db", "hstest");
+ const int keep_connection = arg.sh.conf.get_int("keep_connection", 1);
+ const int verbose = arg.sh.conf.get_int("verbose", 1);
+ const int use_handler = arg.sh.conf.get_int("handler", 0);
+ int connected = 0;
+ unsigned int k = 0;
+ string_buffer buf;
+ for (unsigned int i = 0; i < num; ++i) {
+ const int flags = 0;
+ if (connected == 0 && !mysql_real_connect(db, mysql_host.c_str(),
+ mysql_user.c_str(), mysql_user.empty() ? 0 : mysql_passwd.c_str(),
+ mysql_dbname.c_str(), mysql_port, 0, flags)) {
+ err = "failed to connect: " + std::string(mysql_error(db));
+ if (verbose >= 1) {
+ fprintf(stderr, "e=[%s]\n", err.c_str());
+ }
+ ++err_cnt;
+ return;
+ }
+ int r = 0;
+ if (connected == 0 && use_handler) {
+ const char *const q = "handler hstest open";
+ r = mysql_real_query(db, q, strlen(q));
+ if (r != 0) {
+ err = 1;
+ }
+ }
+ connected = 1;
+ std::string result_str;
+ unsigned int err = 0;
+ unsigned int num_flds = 0, num_affected_rows = 0;
+ int got_data = 0;
+ buf.clear();
+ buf.append_literal("insert into hstest values ");
+ for (size_t j = 0; j < pipe; ++j) {
+ const unsigned int v = ~k;
+ if (j != 0) {
+ buf.append_literal(",");
+ }
+ char *wp = buf.make_space(64);
+ int buf_query_len = snprintf(wp, 64, "('k%u', 'v%u')", k, v);
+ buf.space_wrote(buf_query_len);
+ ++k;
+ }
+ if (r == 0) {
+ r = mysql_real_query(db, buf.begin(), buf.size());
+ ++query_cnt;
+ }
+ if (r != 0) {
+ err = 1;
+ } else {
+ auto_mysql_res res(db);
+ if (res != 0) {
+ if (verbose >= 0) {
+ num_flds = mysql_num_fields(res);
+ MYSQL_ROW row = 0;
+ while ((row = mysql_fetch_row(res)) != 0) {
+ got_data = 1;
+ unsigned long *const lengths = mysql_fetch_lengths(res);
+ if (verbose >= 2) {
+ for (unsigned int i = 0; i < num_flds; ++i) {
+ if (!result_str.empty()) {
+ result_str += " ";
+ }
+ result_str += std::string(row[i], lengths[i]);
+ }
+ }
+ }
+ }
+ } else {
+ if (mysql_field_count(db) == 0) {
+ num_affected_rows = mysql_affected_rows(db);
+ } else {
+ err = 1;
+ }
+ }
+ }
+ if (verbose >= 2 || (verbose >= 1 && err != 0)) {
+ if (err) {
+ ++err_cnt;
+ const char *const errstr = mysql_error(db);
+ fprintf(stderr, "e=[%s] a=%u q=[%s]\n", errstr,
+ num_affected_rows, std::string(buf.begin(), buf.size()).c_str());
+ } else {
+ fprintf(stderr, "a=%u q=[%s] r=[%s]\n", num_affected_rows,
+ std::string(buf.begin(), buf.size()).c_str(),
+ result_str.c_str());
+ }
+ }
+ if (err == 0) {
+ ++io_success_count;
+ if (num_affected_rows > 0 || got_data > 0) {
+ ++op_success_count;
+ }
+ arg.sh.increment_count(pipe);
+ }
+ if (!keep_connection) {
+ db.reset();
+ connected = 0;
+ }
+ }
+ if (verbose >= 1) {
+ fprintf(stderr, "thread finished (error_count=%llu)\n", err_cnt);
+ }
+}
+
+void
+hstest_thread::test_21(int num)
+{
+ /* fsync test */
+ unsigned int id = arg.id;
+ std::string err;
+ #if 0
+ if (socket_connect(fd, arg.sh.arg, err) != 0) {
+ fprintf(stderr, "connect: %d %s\n", errno, strerror(errno));
+ return;
+ }
+ #endif
+ auto_file logfd;
+ char fname[1024];
+ snprintf(fname, sizeof(fname), "synctest_%u", id);
+ int open_flags = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND;
+ logfd.reset(open(fname, open_flags, 0644));
+ if (logfd.get() < 0) {
+ fprintf(stderr, "open: %s: %d %s\n", fname, errno, strerror(errno));
+ return;
+ }
+ char buf[1024];
+ unsigned long long count = 0;
+ while (true) {
+ snprintf(buf, sizeof(buf), "%u %llu\n", id, count);
+ const size_t len = strlen(buf);
+ if (write(logfd.get(), buf, len) != (ssize_t)len) {
+ fprintf(stderr, "write: %s: %d %s\n", fname, errno, strerror(errno));
+ return;
+ }
+ #if 0
+ if (write(fd.get(), buf, len) != (ssize_t)len) {
+ fprintf(stderr, "write(sock): %d %s\n", errno, strerror(errno));
+ return;
+ }
+ #endif
+ if (fdatasync(logfd.get()) != 0) {
+ fprintf(stderr, "fsync: %s: %d %s\n", fname, errno, strerror(errno));
+ return;
+ }
+ ++count;
+ ++op_success_count;
+ arg.sh.increment_count();
+ }
+}
+
+void
+hstest_thread::test_22(int num)
+{
+ /* dd if=/dev/zero of=dummy.dat bs=1024M count=100 */
+ unsigned int id = arg.id;
+ std::string err;
+ auto_file filefd;
+ char fname[1024];
+ snprintf(fname, sizeof(fname), "dummy.dat");
+ int open_flags = O_RDONLY | O_DIRECT;
+ filefd.reset(open(fname, open_flags, 0644));
+ if (filefd.get() < 0) {
+ fprintf(stderr, "open: %s: %d %s\n", fname, errno, strerror(errno));
+ return;
+ }
+ char buf_x[4096 * 2];
+ char *const buf = (char *)(size_t(buf_x + 4096) / 4096 * 4096);
+ unsigned long long count = 0;
+ drand48_data randbuf;
+ unsigned long long seed = time(0);
+ seed *= 10;
+ seed += id;
+ srand48_r(seed, &randbuf);
+ for (unsigned int i = 0; i < arg.sh.loop; ++i) {
+ double kf = 0;
+ drand48_r(&randbuf, &kf);
+ kf *= (209715200 / 1);
+ // fprintf(stderr, "v=%f\n", kf);
+ off_t v = static_cast<off_t>(kf);
+ v %= (209715200 / 1);
+ v *= (512 * 1);
+ const double tm1 = gettimeofday_double();
+ const ssize_t r = pread(filefd.get(), buf, (512 * 1), v);
+ const double tm2 = gettimeofday_double();
+ if (r < 0) {
+ fprintf(stderr, "pread: %s: %d %s\n", fname, errno, strerror(errno));
+ return;
+ }
+ ++count;
+ ++op_success_count;
+ arg.sh.increment_count();
+ set_timing(tm2 - tm1);
+ }
+}
+
+void
+hstest_thread::operator ()()
+{
+ if (arg.watch_flag) {
+ return test_watch();
+ }
+ int test_num = arg.sh.conf.get_int("test", 1);
+ if (test_num == 1) {
+ test_1();
+ } else if (test_num == 2 || test_num == 3) {
+ test_2_3(test_num);
+ } else if (test_num == 4 || test_num == 5) {
+ test_4_5(test_num);
+ } else if (test_num == 6) {
+ test_6(test_num);
+ } else if (test_num == 7) {
+ test_7(test_num);
+ } else if (test_num == 8) {
+ test_8(test_num);
+ } else if (test_num == 9) {
+ test_9(test_num);
+ } else if (test_num == 10) {
+ test_10(test_num);
+ } else if (test_num == 11) {
+ test_11(test_num);
+ } else if (test_num == 12) {
+ test_12(test_num);
+ } else if (test_num == 21) {
+ test_21(test_num);
+ } else if (test_num == 22) {
+ test_22(test_num);
+ }
+ const int halt = arg.sh.conf.get_int("halt", 0);
+ if (halt) {
+ fprintf(stderr, "thread halted\n");
+ while (true) {
+ sleep(100000);
+ }
+ }
+ fprintf(stderr, "thread finished\n");
+}
+
+int
+hstest_main(int argc, char **argv)
+{
+ ignore_sigpipe();
+ hstest_shared shared;
+ parse_args(argc, argv, shared.conf);
+ shared.conf["port"] = shared.conf["hsport"];
+ shared.arg.set(shared.conf);
+ shared.loop = shared.conf.get_int("num", 1000);
+ shared.pipe = shared.conf.get_int("pipe", 1);
+ shared.verbose = shared.conf.get_int("verbose", 1);
+ const int tablesize = shared.conf.get_int("tablesize", 0);
+ std::vector<char> keygen(tablesize);
+ shared.keygen = &keygen[0];
+ shared.keygen_size = tablesize;
+ shared.usleep = shared.conf.get_int("usleep", 0);
+ shared.dump = shared.conf.get_int("dump", 0);
+ shared.num_threads = shared.conf.get_int("num_threads", 10);
+ shared.wait_conn = shared.conf.get_int("wait_conn", 0);
+ const std::string op = shared.conf.get_str("op", "G");
+ if (op.size() > 0) {
+ shared.op = op[0];
+ }
+ #if 0
+ const int localdb_flag = shared.conf.get_int("local", 0);
+ if (localdb_flag) {
+ shared.localdb = database_i::create(shared.conf);
+ }
+ #endif
+ const int num_thrs = shared.num_threads;
+ typedef thread<hstest_thread> thread_type;
+ typedef std::auto_ptr<thread_type> thread_ptr;
+ typedef auto_ptrcontainer< std::vector<thread_type *> > thrs_type;
+ thrs_type thrs;
+ for (int i = 0; i < num_thrs; ++i) {
+ const hstest_thread::arg_type arg(i, shared, false);
+ thread_ptr thr(new thread<hstest_thread>(arg));
+ thrs.push_back_ptr(thr);
+ }
+ for (size_t i = 0; i < thrs.size(); ++i) {
+ thrs[i]->start();
+ }
+ thread_ptr watch_thread;
+ const int timelimit = shared.conf.get_int("timelimit", 0);
+ {
+ const hstest_thread::arg_type arg(0, shared, true);
+ watch_thread = thread_ptr(new thread<hstest_thread>(arg));
+ watch_thread->start();
+ }
+ size_t iocnt = 0, opcnt = 0;
+ double respmin = 999999, respmax = 0;
+ double respsum = 0;
+ if (timelimit != 0) {
+ watch_thread->join();
+ }
+ for (size_t i = 0; i < thrs.size(); ++i) {
+ if (timelimit == 0) {
+ thrs[i]->join();
+ }
+ iocnt += (*thrs[i])->io_success_count;
+ opcnt += (*thrs[i])->op_success_count;
+ respmin = std::min(respmin, (*thrs[i])->response_min);
+ respmax = std::max(respmax, (*thrs[i])->response_max);
+ respsum += (*thrs[i])->response_sum;
+ }
+ fprintf(stderr, "io_success_count=%zu op_success_count=%zu\n", iocnt, opcnt);
+ fprintf(stderr, "respmin=%f respmax=%f respsum=%f respavg=%f\n",
+ respmin, respmax, respsum, respsum / opcnt);
+ size_t keycnt = 0;
+ for (size_t i = 0; i < keygen.size(); ++i) {
+ if (keygen[i]) {
+ ++keycnt;
+ }
+ }
+ fprintf(stderr, "keycnt=%zu\n", keycnt);
+ _exit(0);
+ return 0;
+}
+
+};
+
+int
+main(int argc, char **argv)
+{
+ return dena::hstest_main(argc, argv);
+}
+
diff --git a/plugin/handler_socket/client/hstest.pl b/plugin/handler_socket/client/hstest.pl
new file mode 100755
index 00000000..1363e153
--- /dev/null
+++ b/plugin/handler_socket/client/hstest.pl
@@ -0,0 +1,228 @@
+#!/usr/bin/env perl
+
+# vim:sw=8:ai:ts=8
+
+use strict;
+use warnings;
+
+use DBI;
+use Net::HandlerSocket;
+
+my %conf = ();
+for my $i (@ARGV) {
+ my ($k, $v) = split(/=/, $i);
+ $conf{$k} = $v;
+}
+
+my $verbose = get_conf("verbose", 0);
+my $actions_str = get_conf("actions", "hsread");
+my $tablesize = get_conf("tablesize", 10000);
+my $db = get_conf("db", "hstest");
+my $table = get_conf("table", "hstest_table1");
+my $engine = get_conf("engine", "innodb");
+my $host = get_conf("host", "localhost");
+my $mysqlport = get_conf("mysqlport", 3306);
+my $mysqluser = get_conf("mysqluser", "root");
+my $mysqlpass = get_conf("mysqlpass", "");
+my $hsport = get_conf("hsport", 9999);
+my $loop = get_conf("loop", 10000);
+my $op = get_conf("op", "=");
+my $ssps = get_conf("ssps", 0);
+my $num_moreflds = get_conf("moreflds", 0);
+my $moreflds_prefix = get_conf("moreflds_prefix", "column0123456789_");
+my $keytype = get_conf("keytype", "varchar(32)");
+my $file = get_conf("file", undef);
+
+my $dsn = "DBI:MariaDB:database=;host=$host;port=$mysqlport"
+ . ";mariadb_server_prepare=$ssps";
+my $dbh = DBI->connect($dsn, $mysqluser, $mysqlpass, { RaiseError => 1 });
+my $hsargs = { 'host' => $host, 'port' => $hsport };
+my $cli = new Net::HandlerSocket($hsargs);
+
+my @actions = split(/,/, $actions_str);
+for my $action (@actions) {
+ if ($action eq "table") {
+ print("TABLE $db.$table\n");
+ $dbh->do("drop database if exists $db");
+ $dbh->do("create database $db");
+ $dbh->do("use $db");
+ my $moreflds = get_createtbl_moreflds_str();
+ $dbh->do(
+ "create table $table (" .
+ "k $keytype primary key" .
+ ",v varchar(32) not null" .
+ $moreflds .
+ ") character set utf8 collate utf8_bin " .
+ "engine = $engine");
+ } elsif ($action eq "insert") {
+ print("INSERT $db.$table tablesize=$tablesize\n");
+ $dbh->do("use $db");
+ my $moreflds = get_insert_moreflds_str();
+ for (my $i = 0; $i < $tablesize; $i += 100) {
+ my $qstr = "insert into $db.$table values";
+ for (my $j = 0; $j < 100; ++$j) {
+ if ($j != 0) {
+ $qstr .= ",";
+ }
+ my $k = "" . ($i + $j);
+ my $v = "v" . int(rand(1000)) . ($i + $j);
+ $qstr .= "('$k', '$v'";
+ for (my $j = 0; $j < $num_moreflds; ++$j) {
+ $qstr .= ",'$j'";
+ }
+ $qstr .= ")";
+ }
+ $dbh->do($qstr);
+ print "$i/$tablesize\n" if $i % 1000 == 0;
+ }
+ } elsif ($action eq "read") {
+ print("READ $db.$table op=$op loop=$loop\n");
+ $dbh->do("use $db");
+ my $moreflds = get_select_moreflds_str();
+ my $sth = $dbh->prepare(
+ "select k,v$moreflds from $db.$table where k = ?");
+ for (my $i = 0; $i < $loop; ++$i) {
+ my $k = "" . int(rand($tablesize));
+ # print "k=$k\n";
+ $sth->execute($k);
+ if ($verbose >= 10) {
+ print "RET:";
+ while (my $ref = $sth->fetchrow_arrayref()) {
+ my $rk = $ref->[0];
+ my $rv = $ref->[1];
+ print " $rk $rv";
+ }
+ print "\n";
+ }
+ print "$i/$loop\n" if $i % 1000 == 0;
+ }
+ } elsif ($action eq "hsinsert") {
+ print("HSINSERT $db.$table tablesize=$tablesize\n");
+ $cli->open_index(1, $db, $table, '', 'k,v');
+ for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = "" . $i;
+ my $v = "v" . int(rand(1000)) . $i;
+ my $r = $cli->execute_insert(1, [ $k, $v ]);
+ if ($r->[0] != 0) {
+ die;
+ }
+ print "$i/$tablesize\n" if $i % 1000 == 0;
+ }
+ } elsif ($action eq "hsread") {
+ print("HSREAD $db.$table op=$op loop=$loop\n");
+ my $moreflds = get_select_moreflds_str();
+ $cli->open_index(1, $db, $table, '', "k,v$moreflds");
+ for (my $i = 0; $i < $loop; ++$i) {
+ my $k = "" . int(rand($tablesize));
+ # print "k=$k\n";
+ my $r = $cli->execute_find(1, $op, [ $k ], 1, 0);
+ if ($verbose >= 10) {
+ my $len = scalar(@{$r});
+ print "LEN=$len";
+ for my $e (@{$r}) {
+ print " [$e]";
+ }
+ print "\n";
+ }
+ print "$i/$loop\n" if $i % 1000 == 0;
+ }
+ } elsif ($action eq "hsupdate") {
+ my $vbase = "v" . int(rand(1000));
+ print("HSUPDATE $db.$table op=$op loop=$loop vbase=$vbase\n");
+ $cli->open_index(1, $db, $table, '', 'v');
+ for (my $i = 0; $i < $loop; ++$i) {
+ my $k = "" . int(rand($tablesize));
+ my $v = $vbase . $i;
+ print "k=$k v=$v\n";
+ my $r = $cli->execute_update(1, $op, [ $k ], 1, 0,
+ [ $v ]);
+ if ($verbose >= 10) {
+ print "UP k=$k v=$v\n";
+ }
+ print "$i/$loop\n" if $i % 1000 == 0;
+ }
+ } elsif ($action eq "hsdelete") {
+ print("HSDELETE $db.$table op=$op loop=$loop\n");
+ $cli->open_index(1, $db, $table, '', '');
+ for (my $i = 0; $i < $loop; ++$i) {
+ my $k = "" . int(rand($tablesize));
+ print "k=$k\n";
+ my $r = $cli->execute_delete(1, $op, [ $k ], 1, 0);
+ if ($verbose >= 10) {
+ print "DEL k=$k\n";
+ }
+ print "$i/$loop\n" if $i % 1000 == 0;
+ }
+ } elsif ($action eq "verify") {
+ verify_do();
+ }
+}
+
+sub verify_do {
+ my ($fail_cnt, $ok_cnt) = (0, 0);
+ my $sth = $dbh->prepare("select v from $db.$table where k = ?");
+ use FileHandle;
+ my $fh = new FileHandle($file, "r");
+ while (my $line = <$fh>) {
+ chomp($line);
+ my @vec = split(/\t/, $line);
+ my $k = $vec[3];
+ my $v = $vec[7];
+ next if (!defined($k) || !defined($v));
+ # print "$k $v\n";
+ $sth->execute($k);
+ my $aref = $sth->fetchrow_arrayref();
+ if (!defined($aref)) {
+ print "FAILED: $k notfound\n";
+ ++$fail_cnt;
+ } else {
+ my $gv = $aref->[0];
+ if ($gv ne $v) {
+ print "FAILED: $k got=$gv expected=$v\n";
+ ++$fail_cnt;
+ } else {
+ print "OK: $k $v $gv\n" if $verbose >= 10;
+ ++$ok_cnt;
+ }
+ }
+ }
+ print "OK=$ok_cnt FAIL=$fail_cnt\n";
+}
+
+sub get_conf {
+ my ($key, $def) = @_;
+ my $val = $conf{$key};
+ if ($val) {
+ print "$key=$val\n";
+ } else {
+ $val = $def;
+ $def ||= '';
+ print "$key=$def(default)\n";
+ }
+ return $val;
+}
+
+sub get_createtbl_moreflds_str {
+ my $s = "";
+ for (my $j = 0; $j < $num_moreflds; ++$j) {
+ $s .= ",$moreflds_prefix$j varchar(30)";
+ }
+ return $s;
+}
+
+sub get_select_moreflds_str {
+ my $s = "";
+ for (my $i = 0; $i < $num_moreflds; ++$i) {
+ $s .= ",$moreflds_prefix$i";
+ }
+ return $s;
+}
+
+sub get_insert_moreflds_str {
+ my $s = "";
+ for (my $i = 0; $i < $num_moreflds; ++$i) {
+ $s .= ",?";
+ }
+ return $s;
+}
+
diff --git a/plugin/handler_socket/client/hstest_hs.sh b/plugin/handler_socket/client/hstest_hs.sh
new file mode 100755
index 00000000..1b9eee18
--- /dev/null
+++ b/plugin/handler_socket/client/hstest_hs.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+exec ./hstest test=10 tablesize=10000 host=localhost hsport=9998 num=10000000 \
+ num_threads=100 timelimit=10 $@
diff --git a/plugin/handler_socket/client/hstest_hs_more50.sh b/plugin/handler_socket/client/hstest_hs_more50.sh
new file mode 100755
index 00000000..b7539c52
--- /dev/null
+++ b/plugin/handler_socket/client/hstest_hs_more50.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+exec ./hstest test=10 key_mask=9999 host=localhost port=9998 num=10000000 \
+ num_threads=100 timelimit=10 moreflds=50 $@
diff --git a/plugin/handler_socket/client/hstest_md.sh b/plugin/handler_socket/client/hstest_md.sh
new file mode 100755
index 00000000..8129f884
--- /dev/null
+++ b/plugin/handler_socket/client/hstest_md.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+./hstest test=7 key_mask=9999 host=localhost port=11211 num=10000 \
+ num_threads=10 timelimit=10 op=R $@
+./hstest test=7 key_mask=9999 host=localhost port=11211 num=1000000 \
+ num_threads=100 timelimit=10 op=G $@
+
diff --git a/plugin/handler_socket/client/hstest_my.sh b/plugin/handler_socket/client/hstest_my.sh
new file mode 100755
index 00000000..cf917cf4
--- /dev/null
+++ b/plugin/handler_socket/client/hstest_my.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+exec ./hstest test=9 tablesize=9999 host=localhost mysqlport=3306 num=1000000 \
+ num_threads=100 verbose=1 timelimit=10 $@
diff --git a/plugin/handler_socket/client/hstest_my_more50.sh b/plugin/handler_socket/client/hstest_my_more50.sh
new file mode 100755
index 00000000..6782b5e8
--- /dev/null
+++ b/plugin/handler_socket/client/hstest_my_more50.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+exec ./hstest test=9 key_mask=9999 host=localhost port=3306 num=1000000 \
+ num_threads=100 verbose=1 timelimit=10 moreflds=50 $@
diff --git a/plugin/handler_socket/configure.ac b/plugin/handler_socket/configure.ac
new file mode 100644
index 00000000..4395fcf1
--- /dev/null
+++ b/plugin/handler_socket/configure.ac
@@ -0,0 +1,144 @@
+# -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+#AC_PREREQ([2.63b])
+AC_INIT([handlersocket-plugin], [1.0.6], [https://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL/issues])
+AC_CONFIG_HEADERS([config.h])
+AM_INIT_AUTOMAKE([-Wall -Werror foreign])
+AC_CONFIG_SRCDIR([libhsclient/fatal.cpp])
+AC_CONFIG_MACRO_DIR([m4])
+
+AC_PROG_CC
+AC_PROG_CXX
+AC_PROG_CPP
+AC_PROG_LIBTOOL
+
+ac_mysql_debug=
+AC_ARG_ENABLE(mysql-debug,
+ [AS_HELP_STRING([--enable-mysql-debug], [specify whether MySQL is build with DBUG_ON])],[ac_mysql_debug="$enableval"],[ac_mysql_debug=no])
+AC_MSG_CHECKING([if --enable-mysql-debug is specified])
+AC_MSG_RESULT($ac_mysql_debug)
+
+AC_DEFUN([CONFIG_OPTION_MYSQL],[
+ AC_MSG_CHECKING([mysql source])
+
+ MYSQL_SOURCE_VERSION=
+ MYSQL_INC=
+ ac_mysql_source_dir=
+ AC_ARG_WITH([mysql-source],
+ [AS_HELP_STRING([--with-mysql-source=PATH], [MySQL source directory PATH])],
+ [
+ ac_mysql_source_dir=`cd $withval && pwd`
+ if test -f "$ac_mysql_source_dir/sql/handler.h" ; then
+ MYSQL_INC="-I$ac_mysql_source_dir/sql"
+ MYSQL_INC="$MYSQL_INC -I$ac_mysql_source_dir/include"
+ MYSQL_INC="$MYSQL_INC -I$ac_mysql_source_dir/regex"
+ MYSQL_INC="$MYSQL_INC -I$ac_mysql_source_dir"
+ AC_SUBST(MYSQL_INC)
+ if test -f "$ac_mysql_source_dir/VERSION"; then
+ source "$ac_mysql_source_dir/VERSION"
+ MYSQL_SOURCE_VERSION="$MYSQL_VERSION_MAJOR.$MYSQL_VERSION_MINOR.$MYSQL_VERSION_PATCH"
+ else
+ if test -f "$ac_mysql_source_dir/configure.in"; then
+ MYSQL_SOURCE_VERSION=`cat $ac_mysql_source_dir/configure.in | grep "\[[MySQL Server\]]" | sed -e "s|.*\([[0-9]]\+\.[[0-9]]\+\.[[0-9]]\+[[0-9a-zA-Z\_\-]]*\).*|\1|"`
+ else
+ AC_MSG_ERROR([invalid MySQL source directory: $ac_mysql_source_dir])
+ fi
+ fi
+ AC_MSG_RESULT([yes: Using $ac_mysql_source_dir, version $MYSQL_SOURCE_VERSION])
+ else
+ AC_MSG_ERROR([invalid MySQL source directory: $ac_mysql_source_dir])
+ fi
+ ],
+ [AC_MSG_ERROR([--with-mysql-source=PATH is required for standalone build])]
+ )
+
+ MYSQL_BIN_VERSION=
+ ac_mysql_config=
+ AC_ARG_WITH([mysql-bindir],
+ [AS_HELP_STRING([--with-mysql-bindir=PATH], [MySQL binary directory PATH. This should be the directory where mysql_config is located.])],
+ [
+ mysql_bin_dir=`cd $withval 2> /dev/null && pwd || echo ""`
+ ac_mysql_config="$mysql_bin_dir/mysql_config"
+ ],
+ [
+ AC_PATH_PROG([ac_mysql_config], [mysql_config])
+ ]
+ )
+
+ AC_MSG_CHECKING([mysql binary])
+ if test ! -x "$ac_mysql_config" ; then
+ AC_MSG_ERROR([mysql_config not found! You have to specify the directory where mysql_config resides to --with-mysql-bindir=PATH.])
+ fi
+
+ MYSQL_CFLAGS_ADD=`"$ac_mysql_config" --cflags`
+ MYSQL_CFLAGS="$MYSQL_CFLAGS $MYSQL_CFLAGS_ADD"
+ if test "$ac_mysql_debug" = "yes"; then
+ MYSQL_CFLAGS="$MYSQL_CFLAGS -DDBUG_ON -DENABLED_DEBUG_SYNC"
+ else
+ MYSQL_CFLAGS="$MYSQL_CFLAGS -DDBUG_OFF"
+ fi
+ AC_SUBST(MYSQL_CFLAGS)
+
+ MYSQL_BIN_VERSION=`"$ac_mysql_config" --version`
+ AC_MSG_RESULT([yes: Using $ac_mysql_config, version $MYSQL_BIN_VERSION])
+
+ MYSQL_LIB=`"$ac_mysql_config" --libs_r`
+ LIB_DIR=`echo $MYSQL_LIB | sed -e "s|.*-L/|/|" | sed -e "s| .*||"`
+ # FIXME
+ if test a`basename "$LIB_DIR"` = amysql ; then
+ MYSQL_LIB="-L`dirname $LIB_DIR` $MYSQL_LIB"
+ # FIXME
+ fi
+ AC_SUBST(MYSQL_LIB)
+
+ if test a$MYSQL_SOURCE_VERSION != a$MYSQL_BIN_VERSION ; then
+ AC_MSG_ERROR([MySQL source version does not match MySQL binary version])
+ fi
+
+ AC_MSG_CHECKING([mysql plugin dir])
+ ac_mysql_plugin_dir=
+ AC_ARG_WITH([mysql-plugindir],
+ [AS_HELP_STRING([--with-mysql-plugindir=PATH], [MySQL plugin directory where handlersocket.so to be copied])],
+ [
+ ac_mysql_plugin_dir=`cd $withval && pwd`
+ if test -d "$ac_mysql_plugin_dir/" ; then
+ PLUGIN_DIR="$ac_mysql_plugin_dir"
+ AC_SUBST(PLUGIN_DIR)
+ AC_MSG_RESULT([yes: Using $ac_mysql_plugin_dir])
+ else
+ AC_MSG_ERROR([invalid MySQL plugin directory : $ac_mysql_plugin_dir])
+ fi
+ ],
+ [
+ LIB_DIR_TMP=`"$ac_mysql_config" --plugindir`
+ if test ! -d "$LIB_DIR_TMP"; then
+ LIB_DIR_TMP=`"$ac_mysql_config" --libs_r | sed -e "s|.*-L/|/|" | sed -e "s| .*||"`/plugin
+ # FIXME
+ fi
+ ac_mysql_plugin_dir=$LIB_DIR_TMP
+ PLUGIN_DIR="$ac_mysql_plugin_dir"
+ AC_SUBST(PLUGIN_DIR)
+ AC_MSG_RESULT([--with-mysql-plugindir was not set. Using $ac_mysql_plugin_dir])
+ ]
+ )
+])
+
+HANDLERSOCKET_SUBDIRS="libhsclient"
+AC_ARG_ENABLE(handlersocket_server,
+ [ --enable-handlersocket-server build HandlerSocket plugin (defalut=yes)])
+if test "$enable_handlersocket_server" != "no"; then
+ CONFIG_OPTION_MYSQL
+ HANDLERSOCKET_SUBDIRS="libhsclient handlersocket client"
+fi
+AC_SUBST(HANDLERSOCKET_SUBDIRS)
+
+CFLAGS="$CFLAGS -Werror"
+CXXFLAGS="$CXXFLAGS -Wall -g -fno-rtti -fno-exceptions -fPIC -DPIC"
+
+AC_CONFIG_FILES([Makefile
+ handlersocket/Makefile
+ libhsclient/Makefile
+ client/Makefile])
+
+AC_OUTPUT
diff --git a/plugin/handler_socket/docs-en/about-handlersocket.en.txt b/plugin/handler_socket/docs-en/about-handlersocket.en.txt
new file mode 100644
index 00000000..73b9cab5
--- /dev/null
+++ b/plugin/handler_socket/docs-en/about-handlersocket.en.txt
@@ -0,0 +1,72 @@
+
+-----------------------------------------------------------------------------
+HandlerSocket plugin for MySQL
+
+Copyright (c) 2010 DeNA Co.,Ltd.
+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 DeNA Co.,Ltd. nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY DeNA Co.,Ltd. "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 DeNA Co.,Ltd. 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.
+
+
+-----------------------------------------------------------------------------
+About HandlerSocket
+
+HandlerSocket is a NoSQL plugin for MySQL. It works as a daemon inside the
+mysqld process, accept tcp connections, and execute requests from clients.
+HandlerSocket does not support SQL queries. Instead, it supports simple CRUD
+operations on tables.
+
+Because of the following reasons, HandlerSocket is much faster than the
+mysqld/libmysql pair in some circumstances:
+
+ - HandlerSocket manipulates data without parsing SQL, which causes less
+ CPU usage.
+ - HandlerSocket reads many requests from clients and executes their
+ requests in bulk, which causes less CPU and disk usage.
+ - HandlerSocket client/server protocol is more compact than the
+ mysql/libmysql pair, which causes less network usage.
+
+The current version of HandlerSocket only works with GNU/Linux. The source
+archive of HandlerSocket includes a C++ and a Perl client libraries.
+Here is a list of other language bindings:
+
+ - PHP
+ http://openpear.org/package/Net_HandlerSocket
+ http://github.com/tz-lom/HSPHP
+ http://code.google.com/p/php-handlersocket/
+ - Java
+ http://code.google.com/p/handlersocketforjava/
+ - Python
+ https://code.launchpad.net/~songofacandy/+junk/pyhandlersocket
+ - Ruby
+ https://github.com/winebarrel/ruby-handlersocket
+ https://github.com/miyucy/handlersocket
+ - JavaScript(Node.js)
+ https://github.com/koichik/node-handlersocket
+
+The home of HandlerSocket is here:
+ https://github.com/DeNADev/HandlerSocket-Plugin-for-MySQL
+
+More documents are available in docs-en/ and docs-ja/ directories.
+
diff --git a/plugin/handler_socket/docs-en/configuration-options.en.txt b/plugin/handler_socket/docs-en/configuration-options.en.txt
new file mode 100644
index 00000000..60fb6d85
--- /dev/null
+++ b/plugin/handler_socket/docs-en/configuration-options.en.txt
@@ -0,0 +1,99 @@
+
+-----------------------------------------------------------------
+handlersocket_verbose (default = 10, min = 0, max = 10000)
+
+ Specify the logging verboseness.
+
+-----------------------------------------------------------------
+handlersocket_address (default = '')
+
+ Specify the address to bind. If empty, it binds to 0.0.0.0.
+
+-----------------------------------------------------------------
+handlersocket_port (default = '9998')
+
+ Specify the port to bind. This option is for the listener for
+ read requests. If empty, the listener is disabled.
+
+-----------------------------------------------------------------
+handlersocket_port_wr (default = '9999')
+
+ Specify the port to bind. This option is for the listener for
+ write requests. If empty, the listener is disabled.
+
+-----------------------------------------------------------------
+handlersocket_epoll (default = 1, min = 0, max = 1)
+
+ Specify whether handlersocket uses epoll for I/O multiplexing.
+
+-----------------------------------------------------------------
+handlersocket_threads (default = 16, min = 1, max = 3000)
+
+ Specify the number of handlersocket worker threads. This option
+ is for the listener for read requests. Recommended value is
+ (the number of CPU cores * 2).
+
+-----------------------------------------------------------------
+handlersocket_threads_wr (default = 1, min = 1, max = 3000)
+
+ Specify the number of handlersocket worker threads. This option
+ is for the listener for write requests. Recommended value is 1.
+
+-----------------------------------------------------------------
+handlersocket_timeout (default = 300, min = 30, max = 3600)
+
+ Specify the socket timeout in seconds.
+
+-----------------------------------------------------------------
+handlersocket_backlog (default = 32768, min = 5, max = 1000000)
+
+ Specify the length of the listen backlog.
+
+-----------------------------------------------------------------
+handlersocket_sndbuf (default = 0, min = 0, max = 1677216)
+
+ Specify the maximum socket send buffer in bytes. If 0, the
+ system-wide default value is set.
+
+-----------------------------------------------------------------
+handlersocket_rcvbuf (default = 0, min = 0, max = 1677216)
+
+ Specify the maximum socket receive buffer in bytes. If 0, the
+ system-wide default value is set.
+
+-----------------------------------------------------------------
+handlersocket_readsize (default = 0, min = 0, max = 1677216)
+
+ Specify the minimum length of the handlersocket request buffer.
+ Larger value can make handlersocket faster for large requests,
+ but can consume memory. The default value is possibly 4096.
+
+-----------------------------------------------------------------
+handlersocket_accept_balance (default = 0, min = 0, max = 10000)
+
+ When this option is set to non-zero, handlersocket tries to
+ balance accepted connections among threads. Non-zero is
+ recommended if you use persistent connections (i.e., connection
+ pooling on the client side).
+
+-----------------------------------------------------------------
+handlersocket_wrlock_timeout (default = 12, min = 0, max = 3600)
+
+ Specify the lock timeout in seconds. When a write request is
+ performed, handlersocket acquires an advisory lock named
+ 'handlersocket_wr'. This option sets the timeout for the
+ locking.
+
+-----------------------------------------------------------------
+handlersocket_plain_secret (default = '')
+
+ When this option is specified, a plain-text authentication is
+ enabled for the listener for read requests. This option
+ specifies the secret key for the authentication.
+
+-----------------------------------------------------------------
+handlersocket_plain_secret_wr (default = '')
+
+ This option specifies the secret key for the listener for write
+ requests.
+
diff --git a/plugin/handler_socket/docs-en/installation.en.txt b/plugin/handler_socket/docs-en/installation.en.txt
new file mode 100644
index 00000000..0a0616fa
--- /dev/null
+++ b/plugin/handler_socket/docs-en/installation.en.txt
@@ -0,0 +1,92 @@
+1. Building Handlersocket
+
+ Handlersocket mainly consists of libhsclient, handlersocket, and C++/Perl clients. libhsclient is a common library shared from both client and server(plugin). handlersocket is a MySQL daemon plugin.
+ To build Handlersocket, you need both MySQL source code and MySQL binary. It is not required to pre-build MySQL source code, but source itself is needed because Handlersocket depends on MySQL header files that only MySQL source distribution contains. MySQL binary is just a normal MySQL binary distribution. You can use official MySQL binaries provided by Oracle.
+ Since Handlersocket uses daemon plugin interface supported from MySQL 5.1,
+MySQL 5.1 or higher version is required.
+ Please make sure that you use identical MySQL version between MySQL source
+and MySQL binary. Otherwise you might encounter serious problems (i.e. server
+crash, etc).
+ Here are steps to build Handlersocket.
+
+* Get MySQL source code
+
+* Get MySQL binary
+
+* Build Handlersocket
+ $ ./autogen.sh
+ $ ./configure --with-mysql-source=/work/mysql-5.1.50 --with-mysql-bindir=/work/mysql-5.1.50-linux-x86_64-glibc23/bin --with-mysql-plugindir=/work/mysql-5.1.50-linux-x86_64-glibc23/lib/plugin
+
+ --with-mysql-source refers to the top of MySQL source directory (which
+contains the VERSION file or the configure.in file), --with-mysql-bindir
+refers to where MySQL binary executables (i.e. mysql_config) are located,
+and --with-mysql-plugindir refers to a plugin directory where plugin
+libraries (*.so) are installed.
+
+ $ make
+ $ sudo make install
+
+ Both libhsclient and the handlersocket plugin will be installed.
+
+
+2. Using Handlersocket
+
+Append configuration options for handlersocket to my.cnf.
+
+ [mysqld]
+ loose_handlersocket_port = 9998
+ # the port number to bind to (for read requests)
+ loose_handlersocket_port_wr = 9999
+ # the port number to bind to (for write requests)
+ loose_handlersocket_threads = 16
+ # the number of worker threads (for read requests)
+ loose_handlersocket_threads_wr = 1
+ # the number of worker threads (for write requests)
+ open_files_limit = 65535
+ # to allow handlersocket accept many concurrent
+ # connections, make open_files_limit as large as
+ # possible.
+
+Log in to mysql as root, and execute the following query.
+
+ mysql> install plugin handlersocket soname 'handlersocket.so';
+
+If handlersocket.so is successfully installed, it starts
+accepting connections on port 9998 and 9999. Running
+'show processlist' should show handlersocket worker threads.
+
+-----------------------------------------------------------------
+On the client side, you need to install libhsclient for c++ apps
+and perl-Net-HandlerSocket for perl apps. They do not require
+MySQL to compile.
+
+ $ ./autogen.sh
+ $ ./configure --disable-handlersocket-server
+ $ make
+ $ sudo make install
+ $ cd perl-Net-HandlerSocket
+ $ perl Makefile.PL
+ $ make
+ $ sudo make install
+
+-----------------------------------------------------------------
+Alternatively, you can use the rpm installation. If your OS
+supports rpms, you can use the following commands to build and
+install handlersocket rpm packages.
+
+(Server side, installs HandlerSocket plugin)
+ $ ./autogen.sh
+ $ ./configure --with-mysql-source=/work/mysql-5.1.50 --with-mysql-bindir=/work/mysql-5.1.50-linux-x86_64-glibc23/bin --with-mysql-plugindir=/work/mysql-5.1.50-linux-x86_64-glibc23/lib/plugin
+ $ make rpm_cli
+ $ sudo rpm -U dist/RPMS/*/libhsclient*.rpm
+ $ make rpm_c
+ $ sudo rpm -U dist/RPMS/*/handlersocket*.rpm
+
+(Client side, installs client libraries)
+ $ ./autogen.sh
+ $ ./configure --disable-handlersocket-server
+ $ make rpm_cli
+ $ sudo rpm -U dist/RPMS/*/libhsclient*.rpm
+ $ make rpm_perl
+ $ sudo rpm -U dist/RPMS/*/perl-Net-HandlerSocket*.rpm
+
diff --git a/plugin/handler_socket/docs-en/perl-client.en.txt b/plugin/handler_socket/docs-en/perl-client.en.txt
new file mode 100644
index 00000000..cc913851
--- /dev/null
+++ b/plugin/handler_socket/docs-en/perl-client.en.txt
@@ -0,0 +1,134 @@
+
+-----------------------------------------------------------------
+To open a connection to the handlersocket plugin, you need to
+create a Net::HandlerSocket object.
+
+ use Net::HandlerSocket;
+ my $args = { host => 'localhost', port => 9998 };
+ my $hs = new Net::HandlerSocket($args);
+
+-----------------------------------------------------------------
+Before executing table operations, you need to open an index to
+work with.
+
+ my $err = $hs->open_index(3, 'database1', 'table1', 'PRIMARY',
+ 'f1,f2');
+ die $hs->get_error() if $res->[0] != 0;
+
+The first argument for open_index is an integer value which is
+used to identify an open table, which is only valid within the
+same Net::HandlerSocket object. The 4th argument is the name of
+index to open. If 'PRIMARY' is specified, the primary index is
+open. The 5th argument is a comma-separated list of column names.
+
+-----------------------------------------------------------------
+To read a record from a table using an index, call the
+execute_single method.
+
+ my $res = $hs->execute_single(3, '=', [ 'foo' ], 1, 0);
+ die $hs->get_error() if $res->[0] != 0;
+ shift(@$res);
+
+The first argument must be an integer which has specified as the
+first argument for open_index on the same Net::HandlerSocket
+object. The second argument specifies the search operation. The
+current version of handlersocket supports '=', '>=', '<=', '>',
+and '<'. The 3rd argument specifies the key to find, which must
+an arrayref whose length is equal to or smaller than the number
+of key columns of the index. The 4th and the 5th arguments
+specify the maximum number of records to be retrieved, and the
+number of records skipped before retrieving records. The columns
+to be retrieved are specified by the 5th argument for the
+corresponding open_index call.
+
+The execute_single method always returns an arrayref. The first
+element is the error code, which is 0 when no error is occurred.
+The remaining are the field values. If more than one record is
+returned, it is flatten to an 1-dimensional array. For example,
+when 5 records that have 3 columns are returned, you can retrieve
+values using the following code.
+
+ die $hs->get_error() if $res->[0] != 0;
+ shift(@$res);
+ for (my $row = 0; $row < 5; ++$row) {
+ for (my $col = 0; $col < 3; ++$col) {
+ my $value = $res->[$row * 5 + $col];
+ # ...
+ }
+ }
+
+-----------------------------------------------------------------
+To update or delete records, you need to specify more arguments
+for the execute_single method. Note that the Net::HandlerSocket
+object must be connected to a handlersocket worker for write
+operations, which is port 9999 by default.
+(For safety, the port 9998 only allows read operations, and the
+port 9999 allows write operations also. The port 9999 allows
+read operations too, but slower than 9998 because of record
+locking etc.. Port numbers can be changed using the
+'handlersocket_port' and the 'handlersocket_port_wr'
+configuration options of mysqld.)
+
+ my $args = { host => 'localhost', port => 9999 };
+ my $hs = new Net::HandlerSocket($args);
+
+ my $res = $hs->execute_single(3, '=', [ 'bar' ], 1, 0, 'U',
+ [ 'fubar', 'hoge' ]);
+ die $hs->get_error() if $res->[0] != 0;
+ my $num_updated_rows = $res->[1];
+
+ my $res = $hs->execute_single(3, '=', [ 'baz' ], 1, 0, 'D');
+ die $hs->get_error() if $res->[0] != 0;
+ my $num_deleted_rows = $res->[1];
+
+The 6th argument for execute_single specifies the modification
+operation. The current version supports 'U' and 'D'. For the 'U'
+operation, the 7th argument specifies the new value for the row.
+The columns to be modified are specified by the 5th argument for
+the corresponding open_index call. For the 'D' operation, the
+7th argument can be omitted.
+
+-----------------------------------------------------------------
+The execute_single method can be used for inserting records also.
+
+ my $res = $hs->execute_single(3, '+', [ 'foo', 'bar', 'baz' ]);
+ die $hs->get_error() if $res->[0] != 0;
+
+The 3rd argument must be an arrayref whose elements correspond to
+the 5th argument for the corresponding open_index call. If there
+is a column which is not appeared in the 5th argument for the
+open_index, the default value for the column is set.
+
+-----------------------------------------------------------------
+Multiple operations can be executed in a single call. Executing
+multiple operations in a single call is much faster than
+executing them separatedly.
+
+ my $rarr = $hs->execute_multi([
+ [ 0, '>=', [ 'foo' ], 5, 0 ],
+ [ 2, '=', [ 'bar' ], 1, 0 ],
+ [ 4, '<', [ 'baz' ], 10, 5 ],
+ ]);
+ for my $res (@$rarr) {
+ die $hs->get_error() if $res->[0] != 0;
+ shift(@$res);
+ # ...
+ }
+
+-----------------------------------------------------------------
+If handlersocket is configured to authenticate client connections
+(ie., handlersocket_plain_secret or handlersocket_plain_secret_wr
+is set), a client must call 'auth' method before any other
+methods.
+
+ my $res = $hs->auth('password');
+ die $hs->get_error() if $res->[0] != 0;
+
+-----------------------------------------------------------------
+When an error is occurred, the first element of the returned
+arrayref becomes a non-zero value. A negative value indicates
+that an I/O error is occurred and the Net::HandlerSocket object
+should be disposed. A positive value means that the connection is
+still active and the Net::HandlerSocket object can be reused
+later.
+
diff --git a/plugin/handler_socket/docs-en/protocol.en.txt b/plugin/handler_socket/docs-en/protocol.en.txt
new file mode 100644
index 00000000..3518be36
--- /dev/null
+++ b/plugin/handler_socket/docs-en/protocol.en.txt
@@ -0,0 +1,205 @@
+
+----------------------------------------------------------------------------
+The HandlerSocket protocol
+
+----------------------------------------------------------------------------
+Basic syntax
+
+- The HandlerSocket protocol is line-based. Each line ends with LF(0x0a).
+- Each line consists a concatenation of tokens separated by HT(0x09).
+- A token is either NULL or an encoded string. Note that you need to
+ distinguish NULL from an empty string, as most DBMs does so.
+- NULL is expressed as a single NUL(0x00).
+- An encoded string is a string with the following encoding rules.
+ - Characters in the range [0x10 - 0xff] are encoded as itselves.
+ - A character in the range [0x00 - 0x0f] is prefixed by 0x01 and
+ shifted by 0x40. For example, 0x03 is encoded as 0x01 0x43.
+- Note that a string can be empty. A continuation of 0x09 0x09 means that
+ there is an empty string between them. A continuation of 0x09 0x0a means
+ that there is an empty string at the end of the line.
+
+----------------------------------------------------------------------------
+Request and Response
+
+- The HandlerSocket protocol is a simple request/response protocol. After a
+ connection is established, the client side sends a request, and then the
+ server side sends a response.
+- A request/response consists of a single line.
+- Requests can be pipelined; That is, you can send multiple requests (ie.
+ lines) at one time, and receive responses for them at one time.
+
+----------------------------------------------------------------------------
+Opening index
+
+The 'open_index' request has the following syntax.
+
+ P <indexid> <dbname> <tablename> <indexname> <columns> [<fcolumns>]
+
+- <indexid> is a number in decimal.
+- <dbname>, <tablename>, and <indexname> are strings. To open the primary
+ key, use PRIMARY as <indexname>.
+- <columns> is a comma-separated list of column names.
+- <fcolumns> is a comma-separated list of column names. This parameter is
+ optional.
+
+Once an 'open_index' request is issued, the HandlerSocket plugin opens the
+specified index and keep it open until the client connection is closed. Each
+open index is identified by <indexid>. If <indexid> is already open, the old
+open index is closed. You can open the same combination of <dbname>
+<tablename> <indexname> multiple times, possibly with different <columns>.
+For efficiency, keep <indexid> small as far as possible.
+
+----------------------------------------------------------------------------
+Getting data
+
+The 'find' request has the following syntax.
+
+ <indexid> <op> <vlen> <v1> ... <vn> [LIM] [IN] [FILTER ...]
+
+LIM is a sequence of the following parameters.
+
+ <limit> <offset>
+
+IN is a sequence of the following parameters.
+
+ @ <icol> <ivlen> <iv1> ... <ivn>
+
+FILETER is a sequence of the following parameters.
+
+ <ftyp> <fop> <fcol> <fval>
+
+- <indexid> is a number. This number must be an <indexid> specified by a
+ 'open_index' request executed previously on the same connection.
+- <op> specifies the comparison operation to use. The current version of
+ HandlerSocket supports '=', '>', '>=', '<', and '<='.
+- <vlen> indicates the length of the trailing parameters <v1> ... <vn>. This
+ must be smaller than or equal to the number of index columns specified by
+ the <indexname> parameter of the corresponding 'open_index' request.
+- <v1> ... <vn> specify the index column values to fetch.
+- LIM is optional. <limit> and <offset> are numbers. When omitted, it works
+ as if 1 and 0 are specified. These parameter works like LIMIT of SQL.
+ These values don't include the number of records skipped by a filter.
+- IN is optional. It works like WHERE ... IN syntax of SQL. <icol> must be
+ smaller than the number of index columns specified by the <indexname>
+ parameter of the corresponding 'open_index' request. If IN is specified in
+ a find request, the <icol>-th parameter value of <v1> ... <vn> is ignored.
+- FILTERs are optional. A FILTER specifies a filter. <ftyp> is either 'F'
+ (filter) or 'W' (while). <fop> specifies the comparison operation to use.
+ <fcol> must be smaller than the number of columns specified by the
+ <fcolumns> parameter of the corresponding 'open_index' request. Multiple
+ filters can be specified, and work as the logical AND of them. The
+ difference of 'F' and 'W' is that, when a record does not meet the
+ specified condition, 'F' simply skips the record, and 'W' stops the loop.
+
+----------------------------------------------------------------------------
+Updating/Deleting data
+
+The 'find_modify' request has the following syntax.
+
+ <indexid> <op> <vlen> <v1> ... <vn> [LIM] [IN] [FILTER ...] MOD
+
+MOD is a sequence of the following parameters.
+
+ <mop> <m1> ... <mk>
+
+- <mop> is 'U' (update), '+' (increment), '-' (decrement), 'D' (delete),
+ 'U?', '+?', '-?', or 'D?'. If the '?' suffix is specified, it returns
+ the contents of the records before modification (as if it's a 'find'
+ request), instead of the number of modified records.
+- <m1> ... <mk> specifies the column values to set. The length of <m1> ...
+ <mk> must be smaller than or equal to the length of <columns> specified by
+ the corresponding 'open_index' request. If <mop> is 'D', these parameters
+ are ignored. If <mop> is '+' or '-', values must be numeric. If <mop> is
+ '-' and it attempts to change a column value from negative to positive or
+ positive to negative, the column value is not modified.
+
+----------------------------------------------------------------------------
+Inserting data
+
+The 'insert' request has the following syntax.
+
+ <indexid> + <vlen> <v1> ... <vn>
+
+- <vlen> indicates the length of the trailing parameters <v1> ... <vn>. This
+ must be smaller than or equal to the length of <columns> specified by the
+ corresponding 'open_index' request.
+- <v1> ... <vn> specify the column values to set. For columns not in
+ <columns>, the default values for each column are set.
+
+----------------------------------------------------------------------------
+Authentication
+
+The 'auth' request has the following syntax.
+
+ A <atyp> <akey>
+
+- <atyp> must be '1'
+- An 'auth' request succeeds iff <akey> is the correct secret specified by
+ the 'handlersocket_plain_secret' or 'handlersocket_plain_secret_rw'.
+- If an authentication is enabled for a listener, any other requests on a
+ connection fail before an 'auth' request succeeded on the connection.
+
+----------------------------------------------------------------------------
+Response syntax
+
+HandlerSocket returns a response of the following syntax for each request.
+
+ <errorcode> <numcolumns> <r1> ... <rn>
+
+- <errorcode> indicates whether the request has successfully executed or not.
+ '0' means success. Non-zero means an error.
+- <numcolumns> indicates the number of columns of the result set.
+- <r1> ... <rn> is the result set. The length of <r1> ... <rn> is always a
+ multiple of <numcolumns>. It is possible that <r1> ... <rn> is empty.
+
+If <errorcode> is non-zero, <numcolumns> is always 1 and <r1> indicates a
+human-readable error message, though sometimes <r1> is not provided.
+
+----------------------------------------------------------------------------
+Response for 'open_index'
+
+If 'open_index' is succeeded, HandlerSocket returns a line of the following
+syntax.
+
+ 0 1
+
+----------------------------------------------------------------------------
+Response for 'find'
+
+If 'find' is succeeded, HandlerSocket returns a line of the following
+syntax.
+
+ 0 <numcolumns> <r1> ... <rn>
+
+- <numcolumns> always equals to the length of <columns> of the corresponding
+ 'open_index' request.
+- <r1> ... <rn> is the result set. If N rows are found, the length of <r1>
+ ... <rn> becomes ( <numcolumns> * N ).
+
+----------------------------------------------------------------------------
+Response for 'find_modify'
+
+If 'find_modify' is succeeded, HandlerSocket returns a line of the following
+syntax.
+
+ 0 1 <nummod>
+
+- <nummod> is the number of modified rows.
+- As an exception, if the '?' suffix is specified in <mop>, a response has
+ the syntax of a response for 'find' instead.
+
+----------------------------------------------------------------------------
+Response for 'insert'
+
+If 'insert' is succeeded, HanderSocket returns a line of the following
+syntax.
+
+ 0 1
+
+----------------------------------------------------------------------------
+Response for 'auth'
+
+If 'auth' is succeeded, HanderSocket returns a line of the following syntax.
+
+ 0 1
+
diff --git a/plugin/handler_socket/docs-ja/about-handlersocket.ja.txt b/plugin/handler_socket/docs-ja/about-handlersocket.ja.txt
new file mode 100644
index 00000000..2a152e87
--- /dev/null
+++ b/plugin/handler_socket/docs-ja/about-handlersocket.ja.txt
@@ -0,0 +1,51 @@
+
+
+-----------------------------------------------------------------
+ソースコードの利用にあたっての免責事項
+
+本ソフトウェアの開発者および株式会社ディー・エヌ・エーは、本フト
+ウェアの不稼動、稼動不良を含む法律上の瑕疵担保責任、その他保証責
+任を負わないものとします。また、本ソフトウエアの開発者および株式
+会社ディー・エヌ・エーは、本ソフトウェアの商品性、またはお客様の
+特定の目的に対する適合性について、いかなる保証も負わないものとし
+ます。
+
+-----------------------------------------------------------------
+handlersocket pluginについて
+
+mysqlサーバに常駐し、innodb等のストレージエンジンへの直接のアクセ
+スを提供するプラグインです。handlersocketプラグインは自前のリス
+ナーを持ち、専用のクライアントライブラリ(libhsclient)を使ってそれ
+にアクセスします。
+
+mysqlの標準クライアントライブラリ(libmysql)を使ったアクセスと比べ
+て、以下のような利点があります。
+・接続あたりに消費するリソースが少ないため、同時接続数が事実上無
+ 制限。したがって接続数を気にせず持続接続を使えます。
+・高速(単純な参照クエリで3倍〜10倍程度)。
+・通信プロトコルがコンパクト。libmysqlを使うとデータ転送時にレ
+ コード名などが付随するために通信内容が冗長ですが、libhsclientで
+ はデータのみが転送されるため、帯域消費が少なくなります。場合に
+ よっては10倍以上libmysqlのほうが冗長になります。
+
+現在のバージョンでは以下のような処理をサポートしています。
+・指定された索引について、指定された値と完全一致するようなレコー
+ ドを取得。(SELECT ??? FROM tbl WHERE k1 = v1 AND k2 = v2...)。
+ 索引を使わない検索はサポートしていません。
+・指定された索引について、指定された値の位置の前後のレコードを取
+ 得。(SELECT ??? FROM tbl WHERE k1 >= v1 LIMIT 100)
+・前述のような手段で取得したレコードに対するUPDATEとDELETE
+・レコードのINSERT
+
+以下のような言語をサポートします。
+・C++。libhsclientをリンクします。
+・Perl。Net::HandlerSocketをuseします。
+
+現在のバージョンではGNU/Linuxでのみ動作します。
+
+-----------------------------------------------------------------
+既知の問題
+
+・killでhandlersocketスレッドを殺すと、スレッド数が減ったまま回復
+ しません。
+
diff --git a/plugin/handler_socket/docs-ja/installation.ja.txt b/plugin/handler_socket/docs-ja/installation.ja.txt
new file mode 100644
index 00000000..0e8f3513
--- /dev/null
+++ b/plugin/handler_socket/docs-ja/installation.ja.txt
@@ -0,0 +1,88 @@
+
+-----------------------------------------------------------------
+HandlerSocketプラグインのビルド方法(RPMを使わない方法)
+
+以下のようにしてconfigureを実行します。
+
+ $ ./autogen.sh
+ $ ./configure --with-mysql-source=/work/mysql-5.1.50 --with-mysql-bindir=/work/mysql-5.1.50-linux-x86_64-glibc23/bin --with-mysql-plugindir=/work/mysql-5.1.50-linux-x86_64-glibc23/lib/plugin
+
+ここで--with-mysql-sourceにはMySQLのソースコードのトップディレク
+トリを指定します(そこにVERSIONファイルかconfigure.inファイルがなく
+てはなりません)。--with-mysql-bindirにはインストール済みのMySQL
+のmysql_configコマンドが有るディレクトリを指定します。
+その後以下のようにビルド・インストールします。
+
+ $ make
+ $ sudo make install
+
+-----------------------------------------------------------------
+クライアントライブラリのビルド方法(RPMを使わない方法)
+
+クライアントライブラリをビルドする際には、MySQLのソースコードは
+必要ありません。またMySQLがインストールされている必要もありません。
+
+ $ ./autogen.sh
+ $ ./configure --disable-handlersocket-server
+ $ make
+ $ sudo make install
+ $ cd perl-Net-HandlerSocket
+ $ perl Makefile.PL
+ $ make
+ $ sudo make install
+
+-----------------------------------------------------------------
+ビルド方法(RPM)
+
+以下のように実行すれば、rpmパッケージがビルド&インストールされま
+す。
+
+(MySQLサーバ側、HandlerSocketプラグインをインストールする)
+ $ ./autogen.sh
+ $ ./configure --with-mysql-source=/work/mysql-5.1.50 --with-mysql-bindir=/work/mysql-5.1.50-linux-x86_64-glibc23/bin --with-mysql-plugindir=/work/mysql-5.1.50-linux-x86_64-glibc23/lib/plugin
+ $ make rpm_cli
+ $ sudo rpm -U dist/RPMS/*/libhsclient*.rpm
+ $ make rpm_c
+ $ sudo rpm -U dist/RPMS/*/handlersocket*.rpm
+
+(クライアント側、クライアントライブラリをインストールする)
+ $ ./autogen.sh
+ $ ./configure --disable-handlersocket-server
+ $ make rpm_cli
+ $ sudo rpm -U dist/RPMS/*/libhsclient*.rpm
+ $ make rpm_perl
+ $ sudo rpm -U dist/RPMS/*/perl-Net-HandlerSocket*.rpm
+
+-----------------------------------------------------------------
+起動
+
+mysqlを起動した状態で、mysqlの設定ファイル(my.cnf等)に以下の内容を
+追加します。
+
+ [mysqld]
+ handlersocket_port = 9998
+ # handlersocketが接続を受け付けるポート(参照系リクエスト用)
+ handlersocket_port_wr = 9999
+ # handlersocketが接続を受け付けるポート(更新系リクエスト用)
+ handlersocket_address =
+ # handlersocketがバインドするアドレス(空のままでOK)
+ handlersocket_verbose = 0
+ # デバッグ用
+ handlersocket_timeout = 300
+ # 通信タイムアウト(秒)
+ handlersocket_threads = 16
+ # handlersocketのワーカースレッド数
+ thread_concurrency = 128
+ # handlersocketが幾つかのスレッドを占有するため、大きめの
+ # 値を指定してください
+ open_files_limit = 65535
+ # ソケットを大量に開けるようにするため、大きめの値を指定し
+ # てください
+
+以下のクエリを実行します。
+
+ mysql> install plugin handlersocket soname 'handlersocket.so';
+ Query OK, 0 rows affected (0.06 sec)
+
+以上でhandlersocketへクライアントからアクセスできるようになります。
+
diff --git a/plugin/handler_socket/docs-ja/perl-client.ja.txt b/plugin/handler_socket/docs-ja/perl-client.ja.txt
new file mode 100644
index 00000000..90b7e4d6
--- /dev/null
+++ b/plugin/handler_socket/docs-ja/perl-client.ja.txt
@@ -0,0 +1,126 @@
+
+-----------------------------------------------------------------
+handlersocketプラグインへの接続を開くには、Net::HandlerSocketオブ
+ジェクトを作成します。
+
+ use Net::HandlerSocket;
+ my $args = { host => 'localhost', port => 9998 };
+ my $hs = new Net::HandlerSocket($args);
+
+-----------------------------------------------------------------
+検索などの命令を実行する前に、処理対象となる索引を開く必要があり
+ます。
+
+ my $err = $hs->open_index(3, 'database1', 'table1', 'PRIMARY',
+ 'f1,f2');
+ die $hs->get_error() if $res->[0] != 0;
+
+最初の引数は開く索引に付ける番号です。付けた番号は同一の
+Net::HandlerSocketオブジェクトについてのみ有効です。第4引数は開く
+索引の名前で、「PRIMARY」が指定され場合はプライマリキーが開かれま
+す。第5引数は「,」で区切られた列名のリストです。
+
+-----------------------------------------------------------------
+テーブルから索引を使って行を取得するには、execute_singleメソッド
+を呼びます。
+
+ my $res = $hs->execute_single(3, '=', [ 'foo' ], 1, 0);
+ die $hs->get_error() if $res->[0] != 0;
+ shift(@$res);
+
+最初の引数は索引の番号で、同じNet::HandlerSocketオブジェクトへ
+open_indexで付けたものでなければなりません。第2引数には操作を指定
+します。現在のバージョンでは、「=」、「>=」、「<=」、「>」、「<」
+の操作が利用可能です。第3引数は配列への参照で、これは探すべき行の
+キー値を指定します。配列の長さは索引のキーの個数と同じか少ない数
+でなければなりません。第4引数と第5引数はそれぞれ、取得する最大行
+数、取得前に読み飛ばす行数を指定します。取得される列は対応する
+open_index呼び出しの第5引数で指定されたものになります。
+
+execute_singleメソッドは常に配列への参照を返します。最初の要素は
+エラーコードで、これが0ならば成功を表します。残りの要素は列の値で
+す。もし取得されたデータが複数行の場合は、それが一つの配列へ連結
+された形で格納されています。例えば、5行3列のデータの場合、次のよ
+うなコードによってその内容を取得できます。
+
+ die $hs->get_error() if $res->[0] != 0;
+ shift(@$res);
+ for (my $row = 0; $row < 5; ++$row) {
+ for (my $col = 0; $col < 3; ++$col) {
+ my $value = $res->[$row * 5 + $col];
+ # ...
+ }
+ }
+
+-----------------------------------------------------------------
+行を更新または削除するには、更に多くの引数を指定して
+execute_singleメソッドを呼び出します。書き込み処理をするには、
+対象のNet::HandlerSocketオブジェクトは更新用handlersocketワーカ(既
+定ではポート9999)へ接続されたものでなくてはなりません。
+(安全のため、ポート9998は参照処理だけを受け付け、ポート9999は更新
+処理も受け付けるようになっています。ポート9999は参照処理も受け付
+けますが、レコードロック等の影響で遅くなります。ポート番号は
+mysqldの「handlersocket_port」と「handlersocket_port_wr」の設定項
+目で変更できます。)
+
+ my $args = { host => 'localhost', port => 9999 };
+ my $hs = new Net::HandlerSocket($args);
+
+ my $res = $hs->execute_single(3, '=', [ 'bar' ], 1, 0, 'U',
+ [ 'fubar', 'hoge' ]);
+ die $hs->get_error() if $res->[0] != 0;
+ my $num_updated_rows = $res->[1];
+
+ my $res = $hs->execute_single(3, '=', [ 'baz' ], 1, 0, 'D');
+ die $hs->get_error() if $res->[0] != 0;
+ my $num_deleted_rows = $res->[1];
+
+execute_singleの第6引数は変更処理の種類を指定します。現在のバー
+ジョンでは「U」と「D」が利用可能です。「U」については、第7引数で
+新しい値を指定します。更新される列は、対応するopen_index呼び出し
+の第5引数で指定されたものになります。「D」については第7引数は省
+略できます。
+
+-----------------------------------------------------------------
+execute_singleメソッドは列の挿入にも使用できます。
+
+ my $res = $hs->execute_single(3, '+', [ 'foo', 'bar', 'baz' ]);
+ die $hs->get_error() if $res->[0] != 0;
+
+第3引数は、対応するopen_index呼び出しの第5引数の列リストと同じだ
+けの長さの配列への参照でなければなりません。open_index呼び出しの
+第5引数に指定されていない列については、その列の既定値がセットされ
+ます。
+
+-----------------------------------------------------------------
+execute_multiメソッドを使えば、複数のリクエストを一つの呼び出しで
+実行することができます。これはリクエストを個別に実行するより高速
+です。
+
+ my $rarr = $hs->execute_multi([
+ [ 0, '>=', [ 'foo' ], 5, 0 ],
+ [ 2, '=', [ 'bar' ], 1, 0 ],
+ [ 4, '<', [ 'baz' ], 10, 5 ],
+ ]);
+ for my $res (@$rarr) {
+ die $hs->get_error() if $res->[0] != 0;
+ shift(@$res);
+ # ...
+ }
+
+-----------------------------------------------------------------
+もしhandlersocketが接続を認証するように設定されている
+(handlersocket_plain_secret又はhandlersocket_plain_secret_wrがセッ
+トされている)ならば、クライアントは他のメソッド呼び出しの前にauth
+メソッドを呼び出す必要があります。
+
+ my $res = $hs->auth('password');
+ die $hs->get_error() if $res->[0] != 0;
+
+-----------------------------------------------------------------
+エラーが起こると返値の配列参照の最初の要素が0以外になります。負の
+数の場合はI/Oエラーが起こったことを示し、その場合はその
+Net::HandlerSocketオブジェクトは破棄するべきです。正の値の場合は
+接続は維持されているため、そのオブジェクトはそれ以後も再利用でき
+ます。
+
diff --git a/plugin/handler_socket/docs-ja/protocol.ja.txt b/plugin/handler_socket/docs-ja/protocol.ja.txt
new file mode 100644
index 00000000..46cc9932
--- /dev/null
+++ b/plugin/handler_socket/docs-ja/protocol.ja.txt
@@ -0,0 +1,180 @@
+
+----------------------------------------------------------------------------
+handlersocketの通信プロトコル
+
+----------------------------------------------------------------------------
+基本的な構文
+
+・HandlerSocketのプロトコルは行ベース。各行は改行文字(0x0a)で終わる。
+・各行は複数のトークンからなり、トークン間はTAB文字(0x09)で区切られる。
+・トークンはNULLトークンか、文字列トークンのいずれか。
+・NULLトークンは単一のNUL文字(0x00)であらわされる。
+・文字列トークンは、0バイト以上の文字列であらわされる。ただし0x10未満の文字
+ については0x01を前置し、0x40を加えたコードであらわされる。それ以外の文字は
+ その文字自身のコードであらわされる。
+
+----------------------------------------------------------------------------
+リクエストとレスポンス
+
+・HandlerSocketのプロトコルは単純なリクエスト・レスポンスプロトコルになって
+ いる。接続が確立した後は、まずクライアントがリクエストを送る。
+・サーバは、クライアントが送ったリクエストと丁度同じ数の行(レスポンス)を返
+ す。
+・リクエストはパイプライン化してよい。つまりクライアントは前に送ったリクエス
+ トに対する返事(レスポンス)を待たずに次のリクエストを送ってもよい。
+
+----------------------------------------------------------------------------
+インデックスを開く
+
+open_index命令は次のような構文を持つ。
+
+ P <indexid> <dbname> <tablename> <indexname> <columns> [<fcolumns>]
+
+- <indexid>は数字で、同一接続上で後に実行する命令の、対象索引を指定するため
+ に使われる。
+- <dbname>, <tablename>, <indexname>は文字列で、それぞれDB名、テーブル名、
+ 索引の名前を指定する。<indexname>として「PRIMARY」を指定するとプライマリ
+ キーが開かれる。
+- <columns>はカンマ区切りの列名のリスト。
+- <fcolumns>はカンマ区切りの列名のリスト。これは省略することができる。
+
+このopen_index命令が実行されると、HandlerSocketプラグインは指定されたDB、
+テーブル、索引を開く。開かれた索引は接続が閉じられるまで開かれたままになる。
+開かれた索引は<indexid>の数字で識別される。もし既に<indexid>に指定された番号
+の索引が既に開かれている場合は古いほうが閉じられる。この<indexid>はなるべく
+小さな数字を使ったほうが効率が良い。
+
+----------------------------------------------------------------------------
+データ取得
+
+find命令は次のような構文を持つ。
+
+ <indexid> <op> <vlen> <v1> ... <vn> [LIM] [IN] [FILTER ...]
+
+LIMは次のようなパラメータの並び
+
+ <limit> <offset>
+
+INは次のようなパラメータの並び
+
+ @ <icol> <ivlen> <iv1> ... <ivn>
+
+FILTERは次のようなパラメータの並び
+
+ <ftyp> <fop> <fcol> <fval>
+
+- <indexid>は数字で、これは同じ接続上で過去に実行したopen_index命令に指定さ
+ れた数字でなければならない。
+- <op>は比較演算子で、現在のバージョンでは '=', '>', '>=', '<', '<=' をサ
+ ポートしている。
+- <vlen>は後に続くパラメータ<v1> ... <vn>の長さ。この値は対応するopen_index
+ 命令の<indexname>パラメータで指定された索引のキー列の数と同じか小さいもの
+ でなければならない。
+- <v1> ... <vn>は取得するべきキーの値を指定するパラメータ。
+- LIMは省略できる。<limit>と<offset>は数字で、これはSQLのLIMITと同じように
+ はたらく。省略した場合は1と0を指定した場合と同じ動作をする。FILTERによっ
+ て読み飛ばされたレコードは<limit>と<offset>にカウントされない。
+- INは省略できる。指定されると、これはSQLの WHERE ... IN のように動作する。
+ <icol>は対応するopen_index命令の<indexname>パラメータで指定された索引の
+ キー列の数より小さいものでなければならない。INが指定されたときは、find命
+ 令の<v1> ... <vn>のうち<icol>番目の値は無視される。
+- FILTERは省略できる。これは行取得の際のフィルタを指定する。<ftyp>は
+ 'F'(filter)か'W'(while)のいずれかでなければならない。<fop>は比較演算子。
+ <fcol>は数字で、これは対応するopen_index命令の<fcolumns>で指定された列の
+ 数より小さいものでなければならない。複数のフィルタを指定することもでき、
+ その場合は各フィルタのANDと解釈される。'F'と'W'の違いは、条件にあてはま
+ らない行があったときに'F'は単にそれをスキップするが、'W'はその時点でルー
+ プを抜けるという点。
+
+----------------------------------------------------------------------------
+更新と削除
+
+find_modify命令は次のような構文を持つ。
+
+ <indexid> <op> <vlen> <v1> ... <vn> [LIM] [IN] [FILTER ...] MOD
+
+MODは次のようなパラメータの並び
+
+ <mop> <m1> ... <mk>
+
+- <mop>は'U', '+', '-', 'D', 'U?', '+?', '-?', 'D?'のいずれか。'?'が付いた
+ ものは付いていないものとほぼ同じ動作をするが、付いていないものがレスポン
+ スとして更新された行の数を返すのに対し、付いているものは更新される前の行
+ の内容を返す点のみが異なる。'U'は更新、'D'は削除、'+'はインクリメント、
+ '-'はデクリメントを実行する。
+- <m1> ... <mk>はセットされる各列の値。<m1> ... <mk>の長さは対応する
+ open_index命令の<columns>の長さと等しいか小さくなければならない。<mop>が
+ 'D'のときはこれらのパラメータは無視される。<mop>が'+'か'-'のときは、これら
+ の値は数値でなければならない。<mop>が'-'で、それが負数から正数、または正数
+ から負数へ列の値を変更するようなものであった場合は、値は変更されない。
+
+----------------------------------------------------------------------------
+行の挿入
+
+insert命令は次のような構文を持つ。
+
+ <indexid> + <vlen> <v1> ... <vn>
+
+- <vlen>は後に続くパラメータ<v1> ... <vn>の長さ。これは対応するopen_indexの
+ <columns>の長さに等しいか小さくなければならない。
+- <v1> ... <vn>はセットされる各列の値。指定されないかった列についてはその列
+ のデフォルト値がセットされる。
+
+----------------------------------------------------------------------------
+認証
+
+auth命令は次のような構文を持つ。
+
+ A <atyp> <akey>
+
+- <atyp>は現在のバージョンでは'1'のみが有効。
+- 指定された<akey>が、サーバの設定の'handlersocket_plain_secret'や
+ 'handlersocket_plain_secret_wr'に指定された文字列と一致した場合にのみ認証
+ は成功する。
+- HandlerSocketの認証が有効になっているときは、この'auth'が成功しない限りそ
+ れ以外の命令は全て失敗する。
+
+----------------------------------------------------------------------------
+open_indexに対するレスポンス
+
+open_index命令が成功したとき、レスポンスは次の構文を持つ。
+
+ 0 1
+
+----------------------------------------------------------------------------
+findに対するレスポンス
+
+find命令が成功したとき、レスポンスは次の構文を持つ。
+
+ 0 <numcolumns> <r1> ... <rn>
+
+- <numcolumns>はfind命令の対応するopen_index命令に指定した<columns>の長さに
+ 一致する。
+- <r1> ... <rn>は結果セット。もしN行がfind命令で見つかったなら、<r1> ...
+ <rn>の長さは ( <numcolumns> * N )になる。
+
+----------------------------------------------------------------------------
+find_modifyに対するレスポンス
+
+find_modify命令が成功したとき、レスポンスは次の構文を持つ。
+
+ 0 1 <nummod>
+
+- <nummod>は変更された行の数。
+- 例外として、<mop>が'?'の付いたものであった場合には、find命令に対するレスポ
+ ンスと同じ構文のレスポンスを返す。
+
+----------------------------------------------------------------------------
+insertに対するレスポンス
+
+insert命令が成功したとき、レスポンスは次の構文を持つ。
+
+ 0 1
+
+----------------------------------------------------------------------------
+authに対するレスポンス
+
+auth命令が成功したとき、レスポンスは次の構文を持つ。
+
+ 0 1
+
diff --git a/plugin/handler_socket/handlersocket/COPYRIGHT.txt b/plugin/handler_socket/handlersocket/COPYRIGHT.txt
new file mode 100644
index 00000000..41dda127
--- /dev/null
+++ b/plugin/handler_socket/handlersocket/COPYRIGHT.txt
@@ -0,0 +1,27 @@
+
+ Copyright (c) 2010 DeNA Co.,Ltd.
+ 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 DeNA Co.,Ltd. nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY DeNA Co.,Ltd. "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 DeNA Co.,Ltd. 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.
+
diff --git a/plugin/handler_socket/handlersocket/Makefile.am b/plugin/handler_socket/handlersocket/Makefile.am
new file mode 100644
index 00000000..7e47209b
--- /dev/null
+++ b/plugin/handler_socket/handlersocket/Makefile.am
@@ -0,0 +1,8 @@
+pkgplugindir = $(PLUGIN_DIR)
+CXXFLAGS += -fimplicit-templates
+noinst_HEADERS = database.hpp hstcpsvr.hpp hstcpsvr_worker.hpp mysql_incl.hpp
+pkgplugin_LTLIBRARIES = handlersocket.la
+handlersocket_la_LDFLAGS = -module ../libhsclient/libhsclient.la -L$(top_builddir)/libservices -lmysqlservices
+handlersocket_la_CXXFLAGS = $(MYSQL_INC) $(MYSQL_CFLAGS) $(AM_CXXFLAGS) -I$(srcdir)/../libhsclient
+handlersocket_la_SOURCES = database.cpp handlersocket.cpp \
+ hstcpsvr_worker.cpp hstcpsvr.cpp
diff --git a/plugin/handler_socket/handlersocket/Makefile.plain.template b/plugin/handler_socket/handlersocket/Makefile.plain.template
new file mode 100644
index 00000000..4d5f8c10
--- /dev/null
+++ b/plugin/handler_socket/handlersocket/Makefile.plain.template
@@ -0,0 +1,31 @@
+
+MYSQL_INC = HANDLERSOCKET_MYSQL_INC
+MYSQL_LIB = HANDLERSOCKET_MYSQL_LIB
+
+CXX = g++ -Wall -g -fno-rtti -fno-exceptions -fPIC -DPIC
+LIBS = $(MYSQL_LIB) -lhsclient -lpthread -lz
+CXXFLAGS = -I/usr/include/handlersocket $(MYSQL_INC)
+LDFLAGS =
+
+CXXFLAGS += -O3 -DNDEBUG
+
+HANDLERSOCKET_OBJS = database.o hstcpsvr.o hstcpsvr_worker.o
+
+all: handlersocket.so
+
+handlersocket.so: $(HANDLERSOCKET_OBJS) handlersocket.cpp
+ $(CXX) $(CXXFLAGS) -fno-strict-aliasing -shared $^ -o $@ $(LDFLAGS) \
+ -Wl,-soname -Wl,$@ $(LIBS)
+clean:
+ rm -f *.a *.so *.o
+
+LIBDIR = $(shell \
+ if [ -e /usr/lib64/mysql ]; then echo /usr/lib64; else echo /usr/lib; fi)
+
+install: handlersocket.so
+ sudo sh -c 'ulimit -c unlimited ; /etc/init.d/mysql stop ; \
+ cp handlersocket.so handlersocket.so.cpy && \
+ mv handlersocket.so.cpy \
+ $(LIBDIR)/mysql/plugin/handlersocket.so && \
+ /etc/init.d/mysql start'
+
diff --git a/plugin/handler_socket/handlersocket/database.cpp b/plugin/handler_socket/handlersocket/database.cpp
new file mode 100644
index 00000000..937b1177
--- /dev/null
+++ b/plugin/handler_socket/handlersocket/database.cpp
@@ -0,0 +1,1180 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#include <my_global.h>
+#include <string.h>
+
+#include "database.hpp"
+#include "string_util.hpp"
+#include "escape.hpp"
+#include "mysql_incl.hpp"
+
+#define DBG_KEY(x)
+#define DBG_SHUT(x)
+#define DBG_LOCK(x)
+#define DBG_THR(x)
+#define DBG_CMP(x)
+#define DBG_FLD(x)
+#define DBG_FILTER(x)
+#define DBG_REFCNT(x)
+#define DBG_KEYLEN(x)
+#define DBG_DELETED
+
+/* status variables */
+unsigned long long int open_tables_count;
+unsigned long long int close_tables_count;
+unsigned long long int lock_tables_count;
+unsigned long long int unlock_tables_count;
+unsigned long long int index_exec_count;
+
+namespace dena {
+
+prep_stmt::prep_stmt()
+ : dbctx(0), table_id(static_cast<size_t>(-1)),
+ idxnum(static_cast<size_t>(-1))
+{
+}
+prep_stmt::prep_stmt(dbcontext_i *c, size_t tbl, size_t idx,
+ const fields_type& rf, const fields_type& ff)
+ : dbctx(c), table_id(tbl), idxnum(idx), ret_fields(rf), filter_fields(ff)
+{
+ if (dbctx) {
+ dbctx->table_addref(table_id);
+ }
+}
+prep_stmt::~prep_stmt()
+{
+ if (dbctx) {
+ dbctx->table_release(table_id);
+ }
+}
+
+prep_stmt::prep_stmt(const prep_stmt& x)
+ : dbctx(x.dbctx), table_id(x.table_id), idxnum(x.idxnum),
+ ret_fields(x.ret_fields), filter_fields(x.filter_fields)
+{
+ if (dbctx) {
+ dbctx->table_addref(table_id);
+ }
+}
+
+prep_stmt&
+prep_stmt::operator =(const prep_stmt& x)
+{
+ if (this != &x) {
+ if (dbctx) {
+ dbctx->table_release(table_id);
+ }
+ dbctx = x.dbctx;
+ table_id = x.table_id;
+ idxnum = x.idxnum;
+ ret_fields = x.ret_fields;
+ filter_fields = x.filter_fields;
+ if (dbctx) {
+ dbctx->table_addref(table_id);
+ }
+ }
+ return *this;
+}
+
+struct database : public database_i, private noncopyable {
+ database(const config& c);
+ virtual ~database();
+ virtual dbcontext_ptr create_context(bool for_write) volatile;
+ virtual void stop() volatile;
+ virtual const config& get_conf() const volatile;
+ public:
+ int child_running;
+ private:
+ config conf;
+};
+
+struct tablevec_entry {
+ TABLE *table;
+ size_t refcount;
+ bool modified;
+ tablevec_entry() : table(0), refcount(0), modified(false) { }
+};
+
+struct expr_user_lock : private noncopyable {
+ expr_user_lock(THD *thd, int timeout)
+ : lck_key(thd, "handlersocket_wr", 16, &my_charset_latin1),
+ lck_timeout(thd, timeout),
+ lck_func_get_lock(thd, &lck_key, &lck_timeout),
+ lck_func_release_lock(thd, &lck_key)
+ {
+ lck_key.fix_fields(thd, 0);
+ lck_timeout.fix_fields(thd, 0);
+ lck_func_get_lock.fix_fields(thd, 0);
+ lck_func_release_lock.fix_fields(thd, 0);
+ }
+ long long get_lock() {
+ return lck_func_get_lock.val_int();
+ }
+ long long release_lock() {
+ return lck_func_release_lock.val_int();
+ }
+ private:
+ Item_string lck_key;
+ Item_int lck_timeout;
+ Item_func_get_lock lck_func_get_lock;
+ Item_func_release_lock lck_func_release_lock;
+};
+
+struct dbcontext : public dbcontext_i, private noncopyable {
+ dbcontext(volatile database *d, bool for_write);
+ virtual ~dbcontext();
+ virtual void init_thread(const void *stack_botton,
+ volatile int& shutdown_flag);
+ virtual void term_thread();
+ virtual bool check_alive();
+ virtual void lock_tables_if();
+ virtual void unlock_tables_if();
+ virtual bool get_commit_error();
+ virtual void clear_error();
+ virtual void close_tables_if();
+ virtual void table_addref(size_t tbl_id);
+ virtual void table_release(size_t tbl_id);
+ virtual void cmd_open(dbcallback_i& cb, const cmd_open_args& args);
+ virtual void cmd_exec(dbcallback_i& cb, const cmd_exec_args& args);
+ virtual void set_statistics(size_t num_conns, size_t num_active);
+ private:
+ int set_thread_message(const char *fmt, ...)
+ __attribute__((format (printf, 2, 3)));
+ bool parse_fields(TABLE *const table, const char *str,
+ prep_stmt::fields_type& flds);
+ void cmd_insert_internal(dbcallback_i& cb, const prep_stmt& pst,
+ const string_ref *fvals, size_t fvalslen);
+ void cmd_sql_internal(dbcallback_i& cb, const prep_stmt& pst,
+ const string_ref *fvals, size_t fvalslen);
+ void cmd_find_internal(dbcallback_i& cb, const prep_stmt& pst,
+ ha_rkey_function find_flag, const cmd_exec_args& args);
+ size_t calc_filter_buf_size(TABLE *table, const prep_stmt& pst,
+ const record_filter *filters);
+ bool fill_filter_buf(TABLE *table, const prep_stmt& pst,
+ const record_filter *filters, uchar *filter_buf, size_t len);
+ int check_filter(dbcallback_i& cb, TABLE *table, const prep_stmt& pst,
+ const record_filter *filters, const uchar *filter_buf);
+ void resp_record(dbcallback_i& cb, TABLE *const table, const prep_stmt& pst);
+ void dump_record(dbcallback_i& cb, TABLE *const table, const prep_stmt& pst);
+ int modify_record(dbcallback_i& cb, TABLE *const table,
+ const prep_stmt& pst, const cmd_exec_args& args, char mod_op,
+ size_t& modified_count);
+ private:
+ typedef std::vector<tablevec_entry> table_vec_type;
+ typedef std::pair<std::string, std::string> table_name_type;
+ typedef std::map<table_name_type, size_t> table_map_type;
+ private:
+ volatile database *const dbref;
+ bool for_write_flag;
+ THD *thd;
+ MYSQL_LOCK *lock;
+ bool lock_failed;
+ std::auto_ptr<expr_user_lock> user_lock;
+ int user_level_lock_timeout;
+ bool user_level_lock_locked;
+ bool commit_error;
+ std::vector<char> info_message_buf;
+ table_vec_type table_vec;
+ table_map_type table_map;
+};
+
+database::database(const config& c)
+ : child_running(1), conf(c)
+{
+}
+
+database::~database()
+{
+}
+
+dbcontext_ptr
+database::create_context(bool for_write) volatile
+{
+ return dbcontext_ptr(new dbcontext(this, for_write));
+}
+
+void
+database::stop() volatile
+{
+ child_running = false;
+}
+
+const config&
+database::get_conf() const volatile
+{
+ return const_cast<const config&>(conf);
+}
+
+database_ptr
+database_i::create(const config& conf)
+{
+ return database_ptr(new database(conf));
+}
+
+dbcontext::dbcontext(volatile database *d, bool for_write)
+ : dbref(d), for_write_flag(for_write), thd(0), lock(0), lock_failed(false),
+ user_level_lock_timeout(0), user_level_lock_locked(false),
+ commit_error(false)
+{
+ info_message_buf.resize(8192);
+ user_level_lock_timeout = d->get_conf().get_int("wrlock_timeout", 12);
+}
+
+dbcontext::~dbcontext()
+{
+}
+
+namespace {
+
+int
+wait_server_to_start(THD *thd, volatile int& shutdown_flag)
+{
+ int r = 0;
+ DBG_SHUT(fprintf(stderr, "HNDSOCK wsts\n"));
+ pthread_mutex_lock(&LOCK_server_started);
+ while (!mysqld_server_started) {
+ timespec abstime;
+ set_timespec(abstime, 1);
+ pthread_cond_timedwait(&COND_server_started, &LOCK_server_started,
+ &abstime);
+ pthread_mutex_unlock(&LOCK_server_started);
+ pthread_mutex_lock(&thd->mysys_var->mutex);
+ killed_state st = thd->killed;
+ pthread_mutex_unlock(&thd->mysys_var->mutex);
+ DBG_SHUT(fprintf(stderr, "HNDSOCK wsts kst %d\n", (int)st));
+ pthread_mutex_lock(&LOCK_server_started);
+ if (st != NOT_KILLED) {
+ DBG_SHUT(fprintf(stderr, "HNDSOCK wsts kst %d break\n", (int)st));
+ r = -1;
+ break;
+ }
+ if (shutdown_flag) {
+ DBG_SHUT(fprintf(stderr, "HNDSOCK wsts kst shut break\n"));
+ r = -1;
+ break;
+ }
+ }
+ pthread_mutex_unlock(&LOCK_server_started);
+ DBG_SHUT(fprintf(stderr, "HNDSOCK wsts done\n"));
+ return r;
+}
+
+}; // namespace
+
+#define DENA_THR_OFFSETOF(fld) ((char *)(&thd->fld) - (char *)thd)
+
+void
+dbcontext::init_thread(const void *stack_bottom, volatile int& shutdown_flag)
+{
+ DBG_THR(fprintf(stderr, "HNDSOCK init thread\n"));
+ {
+ my_thread_init();
+ thd = new THD(0);
+ thd->thread_stack = (char *)stack_bottom;
+ DBG_THR(fprintf(stderr,
+ "thread_stack = %p sizeof(THD)=%zu sizeof(mtx)=%zu "
+ "O: %zu %zu %zu %zu %zu %zu %zu\n",
+ thd->thread_stack, sizeof(THD), sizeof(mysql_mutex_t),
+ DENA_THR_OFFSETOF(mdl_context),
+ DENA_THR_OFFSETOF(net),
+ DENA_THR_OFFSETOF(LOCK_thd_data),
+ DENA_THR_OFFSETOF(mysys_var),
+ DENA_THR_OFFSETOF(stmt_arena),
+ DENA_THR_OFFSETOF(limit_found_rows),
+ DENA_THR_OFFSETOF(locked_tables_list)));
+ thd->store_globals();
+ thd->system_thread = static_cast<enum_thread_type>(1<<30UL);
+ memset(&thd->net, 0, sizeof(thd->net));
+ if (for_write_flag) {
+ #if MYSQL_VERSION_ID >= 50505
+ thd->variables.option_bits |= OPTION_BIN_LOG;
+ #else
+ thd->options |= OPTION_BIN_LOG;
+ #endif
+ safeFree((char*) thd->db.str);
+ thd->db.str= my_strdup(PSI_NOT_INSTRUMENTED, "handlersocket", MYF(0));
+ thd->db.length= sizeof("handlersocket")-1;
+ }
+ thd->variables.option_bits |= OPTION_TABLE_LOCK;
+ set_current_thd(thd);
+ DBG_THR(fprintf(stderr, "HNDSOCK x0 %p\n", thd));
+ }
+ {
+ thd->thread_id = next_thread_id();
+ server_threads.insert(thd);
+ }
+
+ DBG_THR(fprintf(stderr, "HNDSOCK init thread wsts\n"));
+ wait_server_to_start(thd, shutdown_flag);
+ DBG_THR(fprintf(stderr, "HNDSOCK init thread done\n"));
+
+ thd_proc_info(thd, &info_message_buf[0]);
+ set_thread_message("hs:listening");
+ DBG_THR(fprintf(stderr, "HNDSOCK x1 %p\n", thd));
+
+ lex_start(thd);
+
+ user_lock.reset(new expr_user_lock(thd, user_level_lock_timeout));
+}
+
+int
+dbcontext::set_thread_message(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ const int n = vsnprintf(&info_message_buf[0], info_message_buf.size(),
+ fmt, ap);
+ va_end(ap);
+ return n;
+}
+
+void
+dbcontext::term_thread()
+{
+ DBG_THR(fprintf(stderr, "HNDSOCK thread end %p\n", thd));
+ close_tables_if();
+ set_current_thd(nullptr);
+ {
+ delete thd;
+ thd = 0;
+ my_thread_end();
+ }
+}
+
+bool
+dbcontext::check_alive()
+{
+ pthread_mutex_lock(&thd->mysys_var->mutex);
+ killed_state st = thd->killed;
+ pthread_mutex_unlock(&thd->mysys_var->mutex);
+ DBG_SHUT(fprintf(stderr, "chk HNDSOCK kst %p %p %d %zu\n", thd, &thd->killed,
+ (int)st, sizeof(*thd)));
+ if (st != NOT_KILLED) {
+ DBG_SHUT(fprintf(stderr, "chk HNDSOCK kst %d break\n", (int)st));
+ return false;
+ }
+ return true;
+}
+
+void
+dbcontext::lock_tables_if()
+{
+ if (lock_failed) {
+ return;
+ }
+ if (for_write_flag && !user_level_lock_locked) {
+ if (user_lock->get_lock()) {
+ user_level_lock_locked = true;
+ } else {
+ lock_failed = true;
+ return;
+ }
+ }
+ if (lock == 0) {
+ const size_t num_max = table_vec.size();
+ TABLE **const tables = DENA_ALLOCA_ALLOCATE(TABLE *, num_max + 1);
+ size_t num_open = 0;
+ for (size_t i = 0; i < num_max; ++i) {
+ if (table_vec[i].refcount > 0) {
+ tables[num_open++] = table_vec[i].table;
+ }
+ table_vec[i].modified = false;
+ }
+ #if MYSQL_VERSION_ID >= 50505
+ lock = thd->lock = mysql_lock_tables(thd, &tables[0], num_open, 0);
+ #else
+ bool need_reopen= false;
+ lock = thd->lock = mysql_lock_tables(thd, &tables[0], num_open,
+ MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN, &need_reopen);
+ #endif
+ statistic_increment(lock_tables_count, &LOCK_status);
+ thd_proc_info(thd, &info_message_buf[0]);
+ DENA_VERBOSE(100, fprintf(stderr, "HNDSOCK lock tables %p %p %zu %zu\n",
+ thd, lock, num_max, num_open));
+ if (lock == 0) {
+ lock_failed = true;
+ DENA_VERBOSE(10, fprintf(stderr, "HNDSOCK failed to lock tables %p\n",
+ thd));
+ }
+ if (for_write_flag) {
+ #if MYSQL_VERSION_ID >= 50505
+ thd->set_current_stmt_binlog_format_row();
+ #else
+ thd->current_stmt_binlog_row_based = 1;
+ #endif
+ }
+ DENA_ALLOCA_FREE(tables);
+ }
+ DBG_LOCK(fprintf(stderr, "HNDSOCK tblnum=%d\n", (int)tblnum));
+}
+
+void
+dbcontext::unlock_tables_if()
+{
+ if (lock != 0) {
+ DENA_VERBOSE(100, fprintf(stderr, "HNDSOCK unlock tables %p %p\n",
+ thd, thd->lock));
+ if (for_write_flag) {
+ for (size_t i = 0; i < table_vec.size(); ++i) {
+ if (table_vec[i].modified) {
+ query_cache_invalidate3(thd, table_vec[i].table, 1);
+ table_vec[i].table->file->ha_release_auto_increment();
+ }
+ }
+ }
+ {
+ bool suc = true;
+ #if MYSQL_VERSION_ID >= 50505
+ suc = (trans_commit_stmt(thd) == 0);
+ #else
+ suc = (ha_autocommit_or_rollback(thd, 0) == 0);
+ #endif
+ if (!suc) {
+ commit_error = true;
+ DENA_VERBOSE(10, fprintf(stderr,
+ "HNDSOCK unlock tables: commit failed\n"));
+ }
+ }
+ mysql_unlock_tables(thd, lock);
+ lock = thd->lock = 0;
+ statistic_increment(unlock_tables_count, &LOCK_status);
+ }
+ if (user_level_lock_locked) {
+ if (user_lock->release_lock()) {
+ user_level_lock_locked = false;
+ }
+ }
+}
+
+bool
+dbcontext::get_commit_error()
+{
+ return commit_error;
+}
+
+void
+dbcontext::clear_error()
+{
+ lock_failed = false;
+ commit_error = false;
+}
+
+void
+dbcontext::close_tables_if()
+{
+ unlock_tables_if();
+ DENA_VERBOSE(100, fprintf(stderr, "HNDSOCK close tables\n"));
+ close_thread_tables(thd);
+ thd->mdl_context.release_transactional_locks(thd);
+ if (!table_vec.empty()) {
+ statistic_increment(close_tables_count, &LOCK_status);
+ table_vec.clear();
+ table_map.clear();
+ }
+}
+
+void
+dbcontext::table_addref(size_t tbl_id)
+{
+ table_vec[tbl_id].refcount += 1;
+ DBG_REFCNT(fprintf(stderr, "%p %zu %zu addref\n", this, tbl_id,
+ table_vec[tbl_id].refcount));
+}
+
+void
+dbcontext::table_release(size_t tbl_id)
+{
+ table_vec[tbl_id].refcount -= 1;
+ DBG_REFCNT(fprintf(stderr, "%p %zu %zu release\n", this, tbl_id,
+ table_vec[tbl_id].refcount));
+}
+
+void
+dbcontext::resp_record(dbcallback_i& cb, TABLE *const table,
+ const prep_stmt& pst)
+{
+ char rwpstr_buf[64];
+ String rwpstr(rwpstr_buf, sizeof(rwpstr_buf), &my_charset_bin);
+ const prep_stmt::fields_type& rf = pst.get_ret_fields();
+ const size_t n = rf.size();
+ for (size_t i = 0; i < n; ++i) {
+ uint32_t fn = rf[i];
+ Field *const fld = table->field[fn];
+ DBG_FLD(fprintf(stderr, "fld=%p %zu\n", fld, fn));
+ if (fld->is_null()) {
+ /* null */
+ cb.dbcb_resp_entry(0, 0);
+ } else {
+ fld->val_str(&rwpstr, &rwpstr);
+ const size_t len = rwpstr.length();
+ if (len != 0) {
+ /* non-empty */
+ cb.dbcb_resp_entry(rwpstr.ptr(), rwpstr.length());
+ } else {
+ /* empty */
+ static const char empty_str[] = "";
+ cb.dbcb_resp_entry(empty_str, 0);
+ }
+ }
+ }
+}
+
+void
+dbcontext::dump_record(dbcallback_i& cb, TABLE *const table,
+ const prep_stmt& pst)
+{
+ char rwpstr_buf[64];
+ String rwpstr(rwpstr_buf, sizeof(rwpstr_buf), &my_charset_bin);
+ const prep_stmt::fields_type& rf = pst.get_ret_fields();
+ const size_t n = rf.size();
+ for (size_t i = 0; i < n; ++i) {
+ uint32_t fn = rf[i];
+ Field *const fld = table->field[fn];
+ if (fld->is_null()) {
+ /* null */
+ fprintf(stderr, "NULL");
+ } else {
+ fld->val_str(&rwpstr, &rwpstr);
+ const std::string s(rwpstr.ptr(), rwpstr.length());
+ fprintf(stderr, "[%s]", s.c_str());
+ }
+ }
+ fprintf(stderr, "\n");
+}
+
+int
+dbcontext::modify_record(dbcallback_i& cb, TABLE *const table,
+ const prep_stmt& pst, const cmd_exec_args& args, char mod_op,
+ size_t& modified_count)
+{
+ if (mod_op == 'U') {
+ /* update */
+ handler *const hnd = table->file;
+ uchar *const buf = table->record[0];
+ store_record(table, record[1]);
+ const prep_stmt::fields_type& rf = pst.get_ret_fields();
+ const size_t n = rf.size();
+ for (size_t i = 0; i < n; ++i) {
+ const string_ref& nv = args.uvals[i];
+ uint32_t fn = rf[i];
+ Field *const fld = table->field[fn];
+ if (nv.begin() == 0) {
+ fld->set_null();
+ } else {
+ fld->set_notnull();
+ fld->store(nv.begin(), nv.size(), &my_charset_bin);
+ }
+ }
+ table_vec[pst.get_table_id()].modified = true;
+ const int r = hnd->ha_update_row(table->record[1], buf);
+ if (r != 0 && r != HA_ERR_RECORD_IS_THE_SAME) {
+ return r;
+ }
+ ++modified_count; /* TODO: HA_ERR_RECORD_IS_THE_SAME? */
+ } else if (mod_op == 'D') {
+ /* delete */
+ handler *const hnd = table->file;
+ table_vec[pst.get_table_id()].modified = true;
+ const int r = hnd->ha_delete_row(table->record[0]);
+ if (r != 0) {
+ return r;
+ }
+ ++modified_count;
+ } else if (mod_op == '+' || mod_op == '-') {
+ /* increment/decrement */
+ handler *const hnd = table->file;
+ uchar *const buf = table->record[0];
+ store_record(table, record[1]);
+ const prep_stmt::fields_type& rf = pst.get_ret_fields();
+ const size_t n = rf.size();
+ size_t i = 0;
+ for (i = 0; i < n; ++i) {
+ const string_ref& nv = args.uvals[i];
+ uint32_t fn = rf[i];
+ Field *const fld = table->field[fn];
+ if (fld->is_null() || nv.begin() == 0) {
+ continue;
+ }
+ const long long pval = fld->val_int();
+ const long long llv = atoll_nocheck(nv.begin(), nv.end());
+ /* TODO: llv == 0? */
+ long long nval = 0;
+ if (mod_op == '+') {
+ /* increment */
+ nval = pval + llv;
+ } else {
+ /* decrement */
+ nval = pval - llv;
+ if ((pval < 0 && nval > 0) || (pval > 0 && nval < 0)) {
+ break; /* don't modify */
+ }
+ }
+ fld->store(nval, false);
+ }
+ if (i == n) {
+ /* modify */
+ table_vec[pst.get_table_id()].modified = true;
+ const int r = hnd->ha_update_row(table->record[1], buf);
+ if (r != 0 && r != HA_ERR_RECORD_IS_THE_SAME) {
+ return r;
+ }
+ ++modified_count;
+ }
+ }
+ return 0;
+}
+
+void
+dbcontext::cmd_insert_internal(dbcallback_i& cb, const prep_stmt& pst,
+ const string_ref *fvals, size_t fvalslen)
+{
+ if (!for_write_flag) {
+ return cb.dbcb_resp_short(2, "readonly");
+ }
+ lock_tables_if();
+ if (lock == 0) {
+ return cb.dbcb_resp_short(1, "lock_tables");
+ }
+ if (pst.get_table_id() >= table_vec.size()) {
+ return cb.dbcb_resp_short(2, "tblnum");
+ }
+ TABLE *const table = table_vec[pst.get_table_id()].table;
+ handler *const hnd = table->file;
+ uchar *const buf = table->record[0];
+ empty_record(table);
+ memset(buf, 0, table->s->null_bytes); /* clear null flags */
+ const prep_stmt::fields_type& rf = pst.get_ret_fields();
+ const size_t n = std::min(rf.size(), fvalslen);
+ for (size_t i = 0; i < n; ++i) {
+ uint32_t fn = rf[i];
+ Field *const fld = table->field[fn];
+ if (fvals[i].begin() == 0) {
+ fld->set_null();
+ } else {
+ fld->store(fvals[i].begin(), fvals[i].size(), &my_charset_bin);
+ }
+ }
+ table->next_number_field = table->found_next_number_field;
+ /* FIXME: test */
+ const int r = hnd->ha_write_row(buf);
+ const ulonglong insert_id = table->file->insert_id_for_cur_row;
+ table->next_number_field = 0;
+ table_vec[pst.get_table_id()].modified = true;
+ if (r == 0 && table->found_next_number_field != 0) {
+ return cb.dbcb_resp_short_num64(0, insert_id);
+ }
+ if (r != 0) {
+ return cb.dbcb_resp_short_num(1, r);
+ }
+ return cb.dbcb_resp_short(0, "");
+}
+
+void
+dbcontext::cmd_sql_internal(dbcallback_i& cb, const prep_stmt& pst,
+ const string_ref *fvals, size_t fvalslen)
+{
+ if (fvalslen < 1) {
+ return cb.dbcb_resp_short(2, "syntax");
+ }
+ return cb.dbcb_resp_short(2, "notimpl");
+}
+
+static size_t
+prepare_keybuf(const cmd_exec_args& args, uchar *key_buf, TABLE *table,
+ KEY& kinfo, size_t invalues_index)
+{
+ size_t kplen_sum = 0;
+ DBG_KEY(fprintf(stderr, "SLOW\n"));
+ for (size_t i = 0; i < args.kvalslen; ++i) {
+ const KEY_PART_INFO & kpt = kinfo.key_part[i];
+ string_ref kval = args.kvals[i];
+ if (args.invalues_keypart >= 0 &&
+ static_cast<size_t>(args.invalues_keypart) == i) {
+ kval = args.invalues[invalues_index];
+ }
+ if (kval.begin() == 0) {
+ kpt.field->set_null();
+ } else {
+ kpt.field->set_notnull();
+ }
+ kpt.field->store(kval.begin(), kval.size(), &my_charset_bin);
+ kplen_sum += kpt.store_length;
+ DBG_KEYLEN(fprintf(stderr, "l=%u sl=%zu\n", kpt.length,
+ kpt.store_length));
+ }
+ key_copy(key_buf, table->record[0], &kinfo, kplen_sum);
+ DBG_KEYLEN(fprintf(stderr, "sum=%zu flen=%u\n", kplen_sum,
+ kinfo.key_length));
+ return kplen_sum;
+}
+
+void
+dbcontext::cmd_find_internal(dbcallback_i& cb, const prep_stmt& pst,
+ ha_rkey_function find_flag, const cmd_exec_args& args)
+{
+ const bool debug_out = (verbose_level >= 100);
+ bool need_resp_record = true;
+ char mod_op = 0;
+ const string_ref& mod_op_str = args.mod_op;
+ if (mod_op_str.size() != 0) {
+ if (!for_write_flag) {
+ return cb.dbcb_resp_short(2, "readonly");
+ }
+ mod_op = mod_op_str.begin()[0];
+ need_resp_record = mod_op_str.size() > 1 && mod_op_str.begin()[1] == '?';
+ switch (mod_op) {
+ case 'U': /* update */
+ case 'D': /* delete */
+ case '+': /* increment */
+ case '-': /* decrement */
+ break;
+ default:
+ if (debug_out) {
+ fprintf(stderr, "unknown modop: %c\n", mod_op);
+ }
+ return cb.dbcb_resp_short(2, "modop");
+ }
+ }
+ lock_tables_if();
+ if (lock == 0) {
+ return cb.dbcb_resp_short(1, "lock_tables");
+ }
+ if (pst.get_table_id() >= table_vec.size()) {
+ return cb.dbcb_resp_short(2, "tblnum");
+ }
+ TABLE *const table = table_vec[pst.get_table_id()].table;
+ /* keys */
+ if (pst.get_idxnum() >= table->s->keys) {
+ return cb.dbcb_resp_short(2, "idxnum");
+ }
+ KEY& kinfo = table->key_info[pst.get_idxnum()];
+ if (args.kvalslen > kinfo.user_defined_key_parts) {
+ return cb.dbcb_resp_short(2, "kpnum");
+ }
+ uchar *const key_buf = DENA_ALLOCA_ALLOCATE(uchar, kinfo.key_length);
+ size_t invalues_idx = 0;
+ size_t kplen_sum = prepare_keybuf(args, key_buf, table, kinfo, invalues_idx);
+ /* filters */
+ uchar *filter_buf = 0;
+ if (args.filters != 0) {
+ const size_t filter_buf_len = calc_filter_buf_size(table, pst,
+ args.filters);
+ filter_buf = DENA_ALLOCA_ALLOCATE(uchar, filter_buf_len);
+ if (!fill_filter_buf(table, pst, args.filters, filter_buf,
+ filter_buf_len)) {
+ return cb.dbcb_resp_short(2, "filterblob");
+ }
+ }
+ /* handler */
+ table->read_set = &table->s->all_set;
+ handler *const hnd = table->file;
+ if (!for_write_flag) {
+ hnd->init_table_handle_for_HANDLER();
+ }
+ hnd->ha_index_or_rnd_end();
+ hnd->ha_index_init(pst.get_idxnum(), 1);
+ if (need_resp_record) {
+ cb.dbcb_resp_begin(pst.get_ret_fields().size());
+ }
+ const uint32_t limit = args.limit ? args.limit : 1;
+ uint32_t skip = args.skip;
+ size_t modified_count = 0;
+ int r = 0;
+ bool is_first = true;
+ for (uint32_t cnt = 0; cnt < limit + skip;) {
+ if (is_first) {
+ is_first = false;
+ const key_part_map kpm = (1U << args.kvalslen) - 1;
+ r = hnd->ha_index_read_map(table->record[0], key_buf, kpm, find_flag);
+ } else if (args.invalues_keypart >= 0) {
+ if (++invalues_idx >= args.invalueslen) {
+ break;
+ }
+ kplen_sum = prepare_keybuf(args, key_buf, table, kinfo, invalues_idx);
+ const key_part_map kpm = (1U << args.kvalslen) - 1;
+ r = hnd->ha_index_read_map(table->record[0], key_buf, kpm, find_flag);
+ } else {
+ switch (find_flag) {
+ case HA_READ_BEFORE_KEY:
+ case HA_READ_KEY_OR_PREV:
+ r = hnd->ha_index_prev(table->record[0]);
+ break;
+ case HA_READ_AFTER_KEY:
+ case HA_READ_KEY_OR_NEXT:
+ r = hnd->ha_index_next(table->record[0]);
+ break;
+ case HA_READ_KEY_EXACT:
+ r = hnd->ha_index_next_same(table->record[0], key_buf, kplen_sum);
+ break;
+ default:
+ r = HA_ERR_END_OF_FILE; /* to finish the loop */
+ break;
+ }
+ }
+ if (debug_out) {
+ fprintf(stderr, "r=%d\n", r);
+ if (r == 0 || r == HA_ERR_RECORD_DELETED) {
+ dump_record(cb, table, pst);
+ }
+ }
+ int filter_res = 0;
+ if (r != 0) {
+ /* no-count */
+ } else if (args.filters != 0 && (filter_res = check_filter(cb, table,
+ pst, args.filters, filter_buf)) != 0) {
+ if (filter_res < 0) {
+ break;
+ }
+ } else if (skip > 0) {
+ --skip;
+ } else {
+ /* hit */
+ if (need_resp_record) {
+ resp_record(cb, table, pst);
+ }
+ if (mod_op != 0) {
+ r = modify_record(cb, table, pst, args, mod_op, modified_count);
+ }
+ ++cnt;
+ }
+ if (args.invalues_keypart >= 0 && r == HA_ERR_KEY_NOT_FOUND) {
+ continue;
+ }
+ if (r != 0 && r != HA_ERR_RECORD_DELETED) {
+ break;
+ }
+ }
+ hnd->ha_index_or_rnd_end();
+ if (r != 0 && r != HA_ERR_RECORD_DELETED && r != HA_ERR_KEY_NOT_FOUND &&
+ r != HA_ERR_END_OF_FILE) {
+ /* failed */
+ if (need_resp_record) {
+ /* revert dbcb_resp_begin() and dbcb_resp_entry() */
+ cb.dbcb_resp_cancel();
+ }
+ cb.dbcb_resp_short_num(1, r);
+ } else {
+ /* succeeded */
+ if (need_resp_record) {
+ cb.dbcb_resp_end();
+ } else {
+ cb.dbcb_resp_short_num(0, modified_count);
+ }
+ }
+ DENA_ALLOCA_FREE(filter_buf);
+ DENA_ALLOCA_FREE(key_buf);
+}
+
+size_t
+dbcontext::calc_filter_buf_size(TABLE *table, const prep_stmt& pst,
+ const record_filter *filters)
+{
+ size_t filter_buf_len = 0;
+ for (const record_filter *f = filters; f->op.begin() != 0; ++f) {
+ if (f->val.begin() == 0) {
+ continue;
+ }
+ const uint32_t fn = pst.get_filter_fields()[f->ff_offset];
+ filter_buf_len += table->field[fn]->pack_length();
+ }
+ ++filter_buf_len;
+ /* Field_medium::cmp() calls uint3korr(), which may read 4 bytes.
+ Allocate 1 more byte for safety. */
+ return filter_buf_len;
+}
+
+bool
+dbcontext::fill_filter_buf(TABLE *table, const prep_stmt& pst,
+ const record_filter *filters, uchar *filter_buf, size_t len)
+{
+ memset(filter_buf, 0, len);
+ size_t pos = 0;
+ for (const record_filter *f = filters; f->op.begin() != 0; ++f) {
+ if (f->val.begin() == 0) {
+ continue;
+ }
+ const uint32_t fn = pst.get_filter_fields()[f->ff_offset];
+ Field *const fld = table->field[fn];
+ if ((fld->flags & BLOB_FLAG) != 0) {
+ return false;
+ }
+ fld->store(f->val.begin(), f->val.size(), &my_charset_bin);
+ const size_t packlen = fld->pack_length();
+ memcpy(filter_buf + pos, fld->ptr, packlen);
+ pos += packlen;
+ }
+ return true;
+}
+
+int
+dbcontext::check_filter(dbcallback_i& cb, TABLE *table, const prep_stmt& pst,
+ const record_filter *filters, const uchar *filter_buf)
+{
+ DBG_FILTER(fprintf(stderr, "check_filter\n"));
+ size_t pos = 0;
+ for (const record_filter *f = filters; f->op.begin() != 0; ++f) {
+ const string_ref& op = f->op;
+ const string_ref& val = f->val;
+ const uint32_t fn = pst.get_filter_fields()[f->ff_offset];
+ Field *const fld = table->field[fn];
+ const size_t packlen = fld->pack_length();
+ const uchar *const bval = filter_buf + pos;
+ int cv = 0;
+ if (fld->is_null()) {
+ cv = (val.begin() == 0) ? 0 : -1;
+ } else {
+ cv = (val.begin() == 0) ? 1 : fld->cmp(bval);
+ }
+ DBG_FILTER(fprintf(stderr, "check_filter cv=%d\n", cv));
+ bool cond = true;
+ if (op.size() == 1) {
+ switch (op.begin()[0]) {
+ case '>':
+ DBG_FILTER(fprintf(stderr, "check_filter op: >\n"));
+ cond = (cv > 0);
+ break;
+ case '<':
+ DBG_FILTER(fprintf(stderr, "check_filter op: <\n"));
+ cond = (cv < 0);
+ break;
+ case '=':
+ DBG_FILTER(fprintf(stderr, "check_filter op: =\n"));
+ cond = (cv == 0);
+ break;
+ default:
+ DBG_FILTER(fprintf(stderr, "check_filter op: unknown\n"));
+ cond = false; /* FIXME: error */
+ break;
+ }
+ } else if (op.size() == 2 && op.begin()[1] == '=') {
+ switch (op.begin()[0]) {
+ case '>':
+ DBG_FILTER(fprintf(stderr, "check_filter op: >=\n"));
+ cond = (cv >= 0);
+ break;
+ case '<':
+ DBG_FILTER(fprintf(stderr, "check_filter op: <=\n"));
+ cond = (cv <= 0);
+ break;
+ case '!':
+ DBG_FILTER(fprintf(stderr, "check_filter op: !=\n"));
+ cond = (cv != 0);
+ break;
+ default:
+ DBG_FILTER(fprintf(stderr, "check_filter op: unknown\n"));
+ cond = false; /* FIXME: error */
+ break;
+ }
+ }
+ DBG_FILTER(fprintf(stderr, "check_filter cond: %d\n", (int)cond));
+ if (!cond) {
+ return (f->filter_type == record_filter_type_skip) ? 1 : -1;
+ }
+ if (val.begin() != 0) {
+ pos += packlen;
+ }
+ }
+ return 0;
+}
+
+void
+dbcontext::cmd_open(dbcallback_i& cb, const cmd_open_args& arg)
+{
+ unlock_tables_if();
+ const table_name_type k = std::make_pair(std::string(arg.dbn),
+ std::string(arg.tbl));
+ const table_map_type::const_iterator iter = table_map.find(k);
+ uint32_t tblnum = 0;
+ if (iter != table_map.end()) {
+ tblnum = iter->second;
+ DBG_CMP(fprintf(stderr, "HNDSOCK k=%s tblnum=%d\n", k.c_str(),
+ (int)tblnum));
+ } else {
+ TABLE_LIST tables;
+ TABLE *table = 0;
+ bool refresh = true;
+ const thr_lock_type lock_type = for_write_flag ? TL_WRITE : TL_READ;
+ #if MYSQL_VERSION_ID >= 50505
+ LEX_CSTRING db_name= { arg.dbn, strlen(arg.dbn) };
+ LEX_CSTRING tbl_name= { arg.tbl, strlen(arg.tbl) };
+ tables.init_one_table(&db_name, &tbl_name, 0, lock_type);
+ MDL_REQUEST_INIT(&tables.mdl_request, MDL_key::TABLE, arg.dbn, arg.tbl,
+ for_write_flag ? MDL_SHARED_WRITE : MDL_SHARED_READ, MDL_TRANSACTION);
+ Open_table_context ot_act(thd, 0);
+ if (!open_table(thd, &tables, &ot_act)) {
+ table = tables.table;
+ }
+ #else
+ tables.init_one_table(arg.dbn, arg.tbl, lock_type);
+ table = open_table(thd, &tables, thd->mem_root, &refresh,
+ OPEN_VIEW_NO_PARSE);
+ #endif
+ if (table == 0) {
+ DENA_VERBOSE(20, fprintf(stderr,
+ "HNDSOCK failed to open %p [%s] [%s] [%d]\n",
+ thd, arg.dbn, arg.tbl, static_cast<int>(refresh)));
+ return cb.dbcb_resp_short(1, "open_table");
+ }
+ statistic_increment(open_tables_count, &LOCK_status);
+ table->reginfo.lock_type = lock_type;
+ table->use_all_columns();
+ tblnum = table_vec.size();
+ tablevec_entry e;
+ e.table = table;
+ table_vec.push_back(e);
+ table_map[k] = tblnum;
+ }
+ size_t idxnum = static_cast<size_t>(-1);
+ if (arg.idx[0] >= '0' && arg.idx[0] <= '9') {
+ /* numeric */
+ TABLE *const table = table_vec[tblnum].table;
+ idxnum = atoi(arg.idx);
+ if (idxnum >= table->s->keys) {
+ return cb.dbcb_resp_short(2, "idxnum");
+ }
+ } else {
+ const char *const idx_name_to_open =
+ arg.idx[0] == '\0' ? "PRIMARY" : arg.idx;
+ TABLE *const table = table_vec[tblnum].table;
+ for (uint i = 0; i < table->s->keys; ++i) {
+ KEY& kinfo = table->key_info[i];
+ if (strcmp(kinfo.name.str, idx_name_to_open) == 0) {
+ idxnum = i;
+ break;
+ }
+ }
+ }
+ if (idxnum == size_t(-1)) {
+ return cb.dbcb_resp_short(2, "idxnum");
+ }
+ prep_stmt::fields_type rf;
+ prep_stmt::fields_type ff;
+ if (!parse_fields(table_vec[tblnum].table, arg.retflds, rf)) {
+ return cb.dbcb_resp_short(2, "fld");
+ }
+ if (!parse_fields(table_vec[tblnum].table, arg.filflds, ff)) {
+ return cb.dbcb_resp_short(2, "fld");
+ }
+ prep_stmt p(this, tblnum, idxnum, rf, ff);
+ cb.dbcb_set_prep_stmt(arg.pst_id, p);
+ return cb.dbcb_resp_short(0, "");
+}
+
+bool
+dbcontext::parse_fields(TABLE *const table, const char *str,
+ prep_stmt::fields_type& flds)
+{
+ string_ref flds_sr(str, strlen(str));
+ std::vector<string_ref> fldnms;
+ if (flds_sr.size() != 0) {
+ split(',', flds_sr, fldnms);
+ }
+ for (size_t i = 0; i < fldnms.size(); ++i) {
+ Field **fld = 0;
+ size_t j = 0;
+ for (fld = table->field; *fld; ++fld, ++j) {
+ DBG_FLD(fprintf(stderr, "f %s\n", (*fld)->field_name.str));
+ string_ref fn((*fld)->field_name.str, (*fld)->field_name.length);
+ if (fn == fldnms[i]) {
+ break;
+ }
+ }
+ if (*fld == 0) {
+ DBG_FLD(fprintf(stderr, "UNKNOWN FLD %s [%s]\n", retflds,
+ std::string(fldnms[i].begin(), fldnms[i].size()).c_str()));
+ return false;
+ }
+ DBG_FLD(fprintf(stderr, "FLD %s %zu\n", (*fld)->field_name.str, j));
+ flds.push_back(j);
+ }
+ return true;
+}
+
+enum db_write_op {
+ db_write_op_none = 0,
+ db_write_op_insert = 1,
+ db_write_op_sql = 2,
+};
+
+void
+dbcontext::cmd_exec(dbcallback_i& cb, const cmd_exec_args& args)
+{
+ const prep_stmt& p = *args.pst;
+ if (p.get_table_id() == static_cast<size_t>(-1)) {
+ return cb.dbcb_resp_short(2, "stmtnum");
+ }
+ ha_rkey_function find_flag = HA_READ_KEY_EXACT;
+ db_write_op wrop = db_write_op_none;
+ if (args.op.size() == 1) {
+ switch (args.op.begin()[0]) {
+ case '=':
+ find_flag = HA_READ_KEY_EXACT;
+ break;
+ case '>':
+ find_flag = HA_READ_AFTER_KEY;
+ break;
+ case '<':
+ find_flag = HA_READ_BEFORE_KEY;
+ break;
+ case '+':
+ wrop = db_write_op_insert;
+ break;
+ case 'S':
+ wrop = db_write_op_sql;
+ break;
+ default:
+ return cb.dbcb_resp_short(2, "op");
+ }
+ } else if (args.op.size() == 2 && args.op.begin()[1] == '=') {
+ switch (args.op.begin()[0]) {
+ case '>':
+ find_flag = HA_READ_KEY_OR_NEXT;
+ break;
+ case '<':
+ find_flag = HA_READ_KEY_OR_PREV;
+ break;
+ default:
+ return cb.dbcb_resp_short(2, "op");
+ }
+ } else {
+ return cb.dbcb_resp_short(2, "op");
+ }
+ if (args.kvalslen <= 0) {
+ return cb.dbcb_resp_short(2, "klen");
+ }
+ switch (wrop) {
+ case db_write_op_none:
+ return cmd_find_internal(cb, p, find_flag, args);
+ case db_write_op_insert:
+ return cmd_insert_internal(cb, p, args.kvals, args.kvalslen);
+ case db_write_op_sql:
+ return cmd_sql_internal(cb, p, args.kvals, args.kvalslen);
+ }
+}
+
+void
+dbcontext::set_statistics(size_t num_conns, size_t num_active)
+{
+ if (for_write_flag) {
+ set_thread_message("handlersocket: mode=wr, %zu conns, %zu active",
+ num_conns, num_active);
+ } else {
+ set_thread_message("handlersocket: mode=rd, %zu conns, %zu active",
+ num_conns, num_active);
+ }
+ /*
+ Don't set message buf if it's already in use. This saves slow call to
+ thd_proc_info() (if profiling is enabled)
+ */
+ if (thd->proc_info != &info_message_buf[0])
+ thd_proc_info(thd, &info_message_buf[0]);
+}
+
+};
+
diff --git a/plugin/handler_socket/handlersocket/database.hpp b/plugin/handler_socket/handlersocket/database.hpp
new file mode 100644
index 00000000..a4aee087
--- /dev/null
+++ b/plugin/handler_socket/handlersocket/database.hpp
@@ -0,0 +1,142 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#ifndef DENA_DATABASE_HPP
+#define DENA_DATABASE_HPP
+
+#include <string>
+#include <memory>
+#include <vector>
+#include <stdint.h>
+
+#include "string_buffer.hpp"
+#include "string_ref.hpp"
+#include "config.hpp"
+
+namespace dena {
+
+struct database_i;
+typedef std::auto_ptr<volatile database_i> database_ptr;
+
+struct dbcontext_i;
+typedef std::auto_ptr<dbcontext_i> dbcontext_ptr;
+
+struct database_i {
+ virtual ~database_i() { }
+ virtual dbcontext_ptr create_context(bool for_write) volatile = 0;
+ virtual void stop() volatile = 0;
+ virtual const config& get_conf() const volatile = 0;
+ static database_ptr create(const config& conf);
+};
+
+struct prep_stmt {
+ typedef std::vector<uint32_t> fields_type;
+ private:
+ dbcontext_i *dbctx; /* must be valid while *this is alive */
+ size_t table_id; /* a prep_stmt object holds a refcount of the table */
+ size_t idxnum;
+ fields_type ret_fields;
+ fields_type filter_fields;
+ public:
+ prep_stmt();
+ prep_stmt(dbcontext_i *c, size_t tbl, size_t idx, const fields_type& rf,
+ const fields_type& ff);
+ ~prep_stmt();
+ prep_stmt(const prep_stmt& x);
+ prep_stmt& operator =(const prep_stmt& x);
+ public:
+ size_t get_table_id() const { return table_id; }
+ size_t get_idxnum() const { return idxnum; }
+ const fields_type& get_ret_fields() const { return ret_fields; }
+ const fields_type& get_filter_fields() const { return filter_fields; }
+};
+
+struct dbcallback_i {
+ virtual ~dbcallback_i () { }
+ virtual void dbcb_set_prep_stmt(size_t pst_id, const prep_stmt& v) = 0;
+ virtual const prep_stmt *dbcb_get_prep_stmt(size_t pst_id) const = 0;
+ virtual void dbcb_resp_short(uint32_t code, const char *msg) = 0;
+ virtual void dbcb_resp_short_num(uint32_t code, uint32_t value) = 0;
+ virtual void dbcb_resp_short_num64(uint32_t code, uint64_t value) = 0;
+ virtual void dbcb_resp_begin(size_t num_flds) = 0;
+ virtual void dbcb_resp_entry(const char *fld, size_t fldlen) = 0;
+ virtual void dbcb_resp_end() = 0;
+ virtual void dbcb_resp_cancel() = 0;
+};
+
+enum record_filter_type {
+ record_filter_type_skip = 0,
+ record_filter_type_break = 1,
+};
+
+struct record_filter {
+ record_filter_type filter_type;
+ string_ref op;
+ uint32_t ff_offset; /* offset in filter_fields */
+ string_ref val;
+ record_filter() : filter_type(record_filter_type_skip), ff_offset(0) { }
+};
+
+struct cmd_open_args {
+ size_t pst_id;
+ const char *dbn;
+ const char *tbl;
+ const char *idx;
+ const char *retflds;
+ const char *filflds;
+ cmd_open_args() : pst_id(0), dbn(0), tbl(0), idx(0), retflds(0),
+ filflds(0) { }
+};
+
+struct cmd_exec_args {
+ const prep_stmt *pst;
+ string_ref op;
+ const string_ref *kvals;
+ size_t kvalslen;
+ uint32_t limit;
+ uint32_t skip;
+ string_ref mod_op;
+ const string_ref *uvals; /* size must be pst->retfieelds.size() */
+ const record_filter *filters;
+ int invalues_keypart;
+ const string_ref *invalues;
+ size_t invalueslen;
+ cmd_exec_args() : pst(0), kvals(0), kvalslen(0), limit(0), skip(0),
+ uvals(0), filters(0), invalues_keypart(-1), invalues(0), invalueslen(0) { }
+};
+
+struct dbcontext_i {
+ virtual ~dbcontext_i() { }
+ virtual void init_thread(const void *stack_bottom,
+ volatile int& shutdown_flag) = 0;
+ virtual void term_thread() = 0;
+ virtual bool check_alive() = 0;
+ virtual void lock_tables_if() = 0;
+ virtual void unlock_tables_if() = 0;
+ virtual bool get_commit_error() = 0;
+ virtual void clear_error() = 0;
+ virtual void close_tables_if() = 0;
+ virtual void table_addref(size_t tbl_id) = 0; /* TODO: hide */
+ virtual void table_release(size_t tbl_id) = 0; /* TODO: hide */
+ virtual void cmd_open(dbcallback_i& cb, const cmd_open_args& args) = 0;
+ virtual void cmd_exec(dbcallback_i& cb, const cmd_exec_args& args) = 0;
+ virtual void set_statistics(size_t num_conns, size_t num_active) = 0;
+};
+
+};
+
+extern unsigned long long int open_tables_count;
+extern unsigned long long int close_tables_count;
+extern unsigned long long int lock_tables_count;
+extern unsigned long long int unlock_tables_count;
+#if 0
+extern unsigned long long int index_exec_count;
+#endif
+
+#endif
+
diff --git a/plugin/handler_socket/handlersocket/handlersocket.cpp b/plugin/handler_socket/handlersocket/handlersocket.cpp
new file mode 100644
index 00000000..81334970
--- /dev/null
+++ b/plugin/handler_socket/handlersocket/handlersocket.cpp
@@ -0,0 +1,217 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#include <my_global.h>
+#include <memory>
+#include <string>
+#include <stdio.h>
+
+#include "config.hpp"
+#include "hstcpsvr.hpp"
+#include "string_util.hpp"
+#include "mysql_incl.hpp"
+
+#define DBG_LOG \
+ if (dena::verbose_level >= 100) { \
+ fprintf(stderr, "%s %p\n", __PRETTY_FUNCTION__, this); \
+ }
+#define DBG_DO(x) if (dena::verbose_level >= 100) { x; }
+
+#define DBG_DIR(x)
+
+using namespace dena;
+
+static char *handlersocket_address = 0;
+static char *handlersocket_port = 0;
+static char *handlersocket_port_wr = 0;
+static unsigned int handlersocket_epoll = 1;
+static unsigned int handlersocket_threads = 32;
+static unsigned int handlersocket_threads_wr = 1;
+static unsigned int handlersocket_timeout = 30;
+static unsigned int handlersocket_backlog = 32768;
+static unsigned int handlersocket_sndbuf = 0;
+static unsigned int handlersocket_rcvbuf = 0;
+static unsigned int handlersocket_readsize = 0;
+static unsigned int handlersocket_accept_balance = 0;
+static unsigned int handlersocket_wrlock_timeout = 0;
+static char *handlersocket_plain_secret = 0;
+static char *handlersocket_plain_secret_wr = 0;
+
+struct daemon_handlersocket_data {
+ hstcpsvr_ptr hssvr_rd;
+ hstcpsvr_ptr hssvr_wr;
+};
+
+static int
+daemon_handlersocket_init(void *p)
+{
+ DENA_VERBOSE(10, fprintf(stderr, "handlersocket: initialized\n"));
+ config conf;
+ conf["use_epoll"] = handlersocket_epoll ? "1" : "0";
+ if (handlersocket_address) {
+ conf["host"] = handlersocket_address;
+ }
+ if (handlersocket_port) {
+ conf["port"] = handlersocket_port;
+ }
+ /*
+ * unix domain socket
+ * conf["host"] = "/";
+ * conf["port"] = "/tmp/handlersocket";
+ */
+ if (handlersocket_threads > 0) {
+ conf["num_threads"] = to_stdstring(handlersocket_threads);
+ } else {
+ conf["num_threads"] = "1";
+ }
+ conf["timeout"] = to_stdstring(handlersocket_timeout);
+ conf["listen_backlog"] = to_stdstring(handlersocket_backlog);
+ conf["sndbuf"] = to_stdstring(handlersocket_sndbuf);
+ conf["rcvbuf"] = to_stdstring(handlersocket_rcvbuf);
+ conf["readsize"] = to_stdstring(handlersocket_readsize);
+ conf["accept_balance"] = to_stdstring(handlersocket_accept_balance);
+ conf["wrlock_timeout"] = to_stdstring(handlersocket_wrlock_timeout);
+ std::auto_ptr<daemon_handlersocket_data> ap(new daemon_handlersocket_data);
+ if (handlersocket_port != 0 && handlersocket_port_wr != handlersocket_port) {
+ conf["port"] = handlersocket_port;
+ if (handlersocket_plain_secret) {
+ conf["plain_secret"] = handlersocket_plain_secret;
+ }
+ ap->hssvr_rd = hstcpsvr_i::create(conf);
+ ap->hssvr_rd->start_listen();
+ }
+ if (handlersocket_port_wr != 0) {
+ if (handlersocket_threads_wr > 0) {
+ conf["num_threads"] = to_stdstring(handlersocket_threads_wr);
+ }
+ conf["port"] = handlersocket_port_wr;
+ conf["for_write"] = "1";
+ conf["plain_secret"] = "";
+ if (handlersocket_plain_secret_wr) {
+ conf["plain_secret"] = handlersocket_plain_secret_wr;
+ }
+ ap->hssvr_wr = hstcpsvr_i::create(conf);
+ ap->hssvr_wr->start_listen();
+ }
+ st_plugin_int *const plugin = static_cast<st_plugin_int *>(p);
+ plugin->data = ap.release();
+ return 0;
+}
+
+static int
+daemon_handlersocket_deinit(void *p)
+{
+ DENA_VERBOSE(10, fprintf(stderr, "handlersocket: terminated\n"));
+ st_plugin_int *const plugin = static_cast<st_plugin_int *>(p);
+ daemon_handlersocket_data *ptr =
+ static_cast<daemon_handlersocket_data *>(plugin->data);
+ delete ptr;
+ return 0;
+}
+
+static struct st_mysql_daemon daemon_handlersocket_plugin = {
+ MYSQL_DAEMON_INTERFACE_VERSION
+};
+
+static MYSQL_SYSVAR_UINT(verbose, dena::verbose_level, 0,
+ "0..10000", 0, 0, 10 /* default */, 0, 10000, 0);
+static MYSQL_SYSVAR_UINT(epoll, handlersocket_epoll, PLUGIN_VAR_READONLY,
+ "0..1", 0, 0, 1 /* default */, 0, 1, 0);
+static MYSQL_SYSVAR_STR(address, handlersocket_address,
+ PLUGIN_VAR_READONLY | PLUGIN_VAR_MEMALLOC, "", NULL, NULL, NULL);
+static MYSQL_SYSVAR_STR(port, handlersocket_port,
+ PLUGIN_VAR_READONLY | PLUGIN_VAR_MEMALLOC, "", NULL, NULL, NULL);
+static MYSQL_SYSVAR_STR(port_wr, handlersocket_port_wr,
+ PLUGIN_VAR_READONLY | PLUGIN_VAR_MEMALLOC, "", NULL, NULL, NULL);
+static MYSQL_SYSVAR_UINT(threads, handlersocket_threads, PLUGIN_VAR_READONLY,
+ "1..3000", 0, 0, 16 /* default */, 1, 3000, 0);
+static MYSQL_SYSVAR_UINT(threads_wr, handlersocket_threads_wr,
+ PLUGIN_VAR_READONLY, "1..3000", 0, 0, 1 /* default */, 1, 3000, 0);
+static MYSQL_SYSVAR_UINT(timeout, handlersocket_timeout, PLUGIN_VAR_READONLY,
+ "30..3600", 0, 0, 300 /* default */, 30, 3600, 0);
+static MYSQL_SYSVAR_UINT(backlog, handlersocket_backlog, PLUGIN_VAR_READONLY,
+ "5..1000000", 0, 0, 32768 /* default */, 5, 1000000, 0);
+static MYSQL_SYSVAR_UINT(sndbuf, handlersocket_sndbuf, PLUGIN_VAR_READONLY,
+ "0..16777216", 0, 0, 0 /* default */, 0, 16777216, 0);
+static MYSQL_SYSVAR_UINT(rcvbuf, handlersocket_rcvbuf, PLUGIN_VAR_READONLY,
+ "0..16777216", 0, 0, 0 /* default */, 0, 16777216, 0);
+static MYSQL_SYSVAR_UINT(readsize, handlersocket_readsize, PLUGIN_VAR_READONLY,
+ "0..16777216", 0, 0, 0 /* default */, 0, 16777216, 0);
+static MYSQL_SYSVAR_UINT(accept_balance, handlersocket_accept_balance,
+ PLUGIN_VAR_READONLY, "0..10000", 0, 0, 0 /* default */, 0, 10000, 0);
+static MYSQL_SYSVAR_UINT(wrlock_timeout, handlersocket_wrlock_timeout,
+ PLUGIN_VAR_READONLY, "0..3600", 0, 0, 12 /* default */, 0, 3600, 0);
+static MYSQL_SYSVAR_STR(plain_secret, handlersocket_plain_secret,
+ PLUGIN_VAR_READONLY | PLUGIN_VAR_MEMALLOC, "", NULL, NULL, NULL);
+static MYSQL_SYSVAR_STR(plain_secret_wr, handlersocket_plain_secret_wr,
+ PLUGIN_VAR_READONLY | PLUGIN_VAR_MEMALLOC, "", NULL, NULL, NULL);
+
+
+/* warning: type-punning to incomplete type might break strict-aliasing
+ * rules */
+static struct st_mysql_sys_var *daemon_handlersocket_system_variables[] = {
+ MYSQL_SYSVAR(verbose),
+ MYSQL_SYSVAR(address),
+ MYSQL_SYSVAR(port),
+ MYSQL_SYSVAR(port_wr),
+ MYSQL_SYSVAR(epoll),
+ MYSQL_SYSVAR(threads),
+ MYSQL_SYSVAR(threads_wr),
+ MYSQL_SYSVAR(timeout),
+ MYSQL_SYSVAR(backlog),
+ MYSQL_SYSVAR(sndbuf),
+ MYSQL_SYSVAR(rcvbuf),
+ MYSQL_SYSVAR(readsize),
+ MYSQL_SYSVAR(accept_balance),
+ MYSQL_SYSVAR(wrlock_timeout),
+ MYSQL_SYSVAR(plain_secret),
+ MYSQL_SYSVAR(plain_secret_wr),
+ 0
+};
+
+static SHOW_VAR hs_status_variables[] = {
+ {"table_open", (char*) &open_tables_count, SHOW_LONGLONG},
+ {"table_close", (char*) &close_tables_count, SHOW_LONGLONG},
+ {"table_lock", (char*) &lock_tables_count, SHOW_LONGLONG},
+ {"table_unlock", (char*) &unlock_tables_count, SHOW_LONGLONG},
+ #if 0
+ {"index_exec", (char*) &index_exec_count, SHOW_LONGLONG},
+ #endif
+ {NullS, NullS, SHOW_LONG}
+};
+
+static int show_hs_vars(THD *thd, SHOW_VAR *var, char *buff)
+{
+ var->type= SHOW_ARRAY;
+ var->value= (char *) &hs_status_variables;
+ return 0;
+}
+
+static SHOW_VAR daemon_handlersocket_status_variables[] = {
+ {"Hs", (char*) show_hs_vars, SHOW_FUNC},
+ {NullS, NullS, SHOW_LONG}
+};
+
+
+maria_declare_plugin(handlersocket)
+{
+ MYSQL_DAEMON_PLUGIN,
+ &daemon_handlersocket_plugin,
+ "handlersocket",
+ "higuchi dot akira at dena dot jp",
+ "Direct access into InnoDB",
+ PLUGIN_LICENSE_BSD,
+ daemon_handlersocket_init,
+ daemon_handlersocket_deinit,
+ 0x0100 /* 1.0 */,
+ daemon_handlersocket_status_variables,
+ daemon_handlersocket_system_variables,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_BETA
+}
+maria_declare_plugin_end;
diff --git a/plugin/handler_socket/handlersocket/handlersocket.spec.template b/plugin/handler_socket/handlersocket/handlersocket.spec.template
new file mode 100644
index 00000000..0ce8c0cb
--- /dev/null
+++ b/plugin/handler_socket/handlersocket/handlersocket.spec.template
@@ -0,0 +1,29 @@
+Summary: handlersocket plugin for mysql
+Name: handlersocket
+Version: HANDLERSOCKET_VERSION
+Release: 1%{?dist}
+Group: System Environment/Libraries
+License: BSD
+Source: handlersocket.tar.gz
+Packager: Akira Higuchi <higuchi dot akira at dena dot jp>
+BuildRoot: /var/tmp/%{name}-%{version}-root
+
+%description
+
+%prep
+%setup -n %{name}
+
+%define _use_internal_dependency_generator 0
+
+%build
+make -f Makefile.plain
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT/%{_libdir}/mysql/plugin
+install -m 755 handlersocket.so $RPM_BUILD_ROOT/%{_libdir}/mysql/plugin/
+
+%files
+%defattr(-, root, root)
+%{_libdir}/mysql/plugin/*.so
+
diff --git a/plugin/handler_socket/handlersocket/hstcpsvr.cpp b/plugin/handler_socket/handlersocket/hstcpsvr.cpp
new file mode 100644
index 00000000..250ef2c7
--- /dev/null
+++ b/plugin/handler_socket/handlersocket/hstcpsvr.cpp
@@ -0,0 +1,147 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#include <my_global.h>
+#include <vector>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <sys/resource.h>
+
+#include "hstcpsvr.hpp"
+#include "hstcpsvr_worker.hpp"
+#include "thread.hpp"
+#include "fatal.hpp"
+#include "auto_ptrcontainer.hpp"
+
+#define DBG(x)
+
+namespace dena {
+
+struct worker_throbj {
+ worker_throbj(const hstcpsvr_worker_arg& arg)
+ : worker(hstcpsvr_worker_i::create(arg)) { }
+ void operator ()() {
+ worker->run();
+ }
+ hstcpsvr_worker_ptr worker;
+};
+
+struct hstcpsvr : public hstcpsvr_i, private noncopyable {
+ hstcpsvr(const config& c);
+ ~hstcpsvr();
+ virtual std::string start_listen();
+ private:
+ hstcpsvr_shared_c cshared;
+ volatile hstcpsvr_shared_v vshared;
+ typedef thread<worker_throbj> worker_thread_type;
+ typedef auto_ptrcontainer< std::vector<worker_thread_type *> > threads_type;
+ threads_type threads;
+ std::vector<unsigned int> thread_num_conns_vec;
+ private:
+ void stop_workers();
+};
+
+namespace {
+
+void
+check_nfile(size_t nfile)
+{
+ struct rlimit rl;
+ const int r = getrlimit(RLIMIT_NOFILE, &rl);
+ if (r != 0) {
+ fatal_abort("check_nfile: getrlimit failed");
+ }
+ if (rl.rlim_cur < static_cast<rlim_t>(nfile + 1000)) {
+ fprintf(stderr,
+ "[Warning] handlersocket: open_files_limit is too small.\n");
+ }
+}
+
+};
+
+hstcpsvr::hstcpsvr(const config& c)
+ : cshared(), vshared()
+{
+ vshared.shutdown = 0;
+ cshared.conf = c; /* copy */
+ if (cshared.conf["port"] == "") {
+ cshared.conf["port"] = "9999";
+ }
+ cshared.num_threads = cshared.conf.get_int("num_threads", 32);
+ cshared.sockargs.nonblocking = cshared.conf.get_int("nonblocking", 1);
+ cshared.sockargs.use_epoll = cshared.conf.get_int("use_epoll", 1);
+ if (cshared.sockargs.use_epoll) {
+ cshared.sockargs.nonblocking = 1;
+ }
+ cshared.readsize = cshared.conf.get_int("readsize", 1);
+ cshared.nb_conn_per_thread = cshared.conf.get_int("conn_per_thread", 1024);
+ cshared.for_write_flag = cshared.conf.get_int("for_write", 0);
+ cshared.plain_secret = cshared.conf.get_str("plain_secret", "");
+ cshared.require_auth = !cshared.plain_secret.empty();
+ cshared.sockargs.set(cshared.conf);
+ cshared.dbptr = database_i::create(c);
+ check_nfile(cshared.num_threads * cshared.nb_conn_per_thread);
+ thread_num_conns_vec.resize(cshared.num_threads);
+ cshared.thread_num_conns = thread_num_conns_vec.empty()
+ ? 0 : &thread_num_conns_vec[0];
+}
+
+hstcpsvr::~hstcpsvr()
+{
+ stop_workers();
+}
+
+std::string
+hstcpsvr::start_listen()
+{
+ std::string err;
+ if (threads.size() != 0) {
+ return "start_listen: already running";
+ }
+ if (socket_bind(cshared.listen_fd, cshared.sockargs, err) != 0) {
+ return "bind: " + err;
+ }
+ DENA_VERBOSE(20, fprintf(stderr, "bind done\n"));
+ const size_t stack_size = std::max(
+ cshared.conf.get_int("stack_size", 1 * 1024LL * 1024), 8 * 1024LL * 1024);
+ for (long i = 0; i < cshared.num_threads; ++i) {
+ hstcpsvr_worker_arg arg;
+ arg.cshared = &cshared;
+ arg.vshared = &vshared;
+ arg.worker_id = i;
+ std::auto_ptr< thread<worker_throbj> > thr(
+ new thread<worker_throbj>(arg, stack_size));
+ threads.push_back_ptr(thr);
+ }
+ DENA_VERBOSE(20, fprintf(stderr, "threads created\n"));
+ for (size_t i = 0; i < threads.size(); ++i) {
+ threads[i]->start();
+ }
+ DENA_VERBOSE(20, fprintf(stderr, "threads started\n"));
+ return std::string();
+}
+
+void
+hstcpsvr::stop_workers()
+{
+ vshared.shutdown = 1;
+ for (size_t i = 0; i < threads.size(); ++i) {
+ threads[i]->join();
+ }
+ threads.clear();
+}
+
+hstcpsvr_ptr
+hstcpsvr_i::create(const config& conf)
+{
+ return hstcpsvr_ptr(new hstcpsvr(conf));
+}
+
+};
+
diff --git a/plugin/handler_socket/handlersocket/hstcpsvr.hpp b/plugin/handler_socket/handlersocket/hstcpsvr.hpp
new file mode 100644
index 00000000..811bfa25
--- /dev/null
+++ b/plugin/handler_socket/handlersocket/hstcpsvr.hpp
@@ -0,0 +1,58 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#ifndef DENA_HSTCPSVR_HPP
+#define DENA_HSTCPSVR_HPP
+
+#include <memory>
+#include <string>
+#include <map>
+
+#include "mutex.hpp"
+#include "auto_file.hpp"
+#include "database.hpp"
+#include "config.hpp"
+#include "socket.hpp"
+
+namespace dena {
+
+struct hstcpsvr_shared_c {
+ config conf;
+ long num_threads;
+ long nb_conn_per_thread;
+ bool for_write_flag;
+ bool require_auth;
+ std::string plain_secret;
+ int readsize;
+ socket_args sockargs;
+ auto_file listen_fd;
+ database_ptr dbptr;
+ volatile unsigned int *thread_num_conns; /* 0 .. num_threads-1 */
+ hstcpsvr_shared_c() : num_threads(0), nb_conn_per_thread(100),
+ for_write_flag(false), require_auth(false), readsize(0),
+ thread_num_conns(0) { }
+};
+
+struct hstcpsvr_shared_v : public mutex {
+ int shutdown;
+ hstcpsvr_shared_v() : shutdown(0) { }
+};
+
+struct hstcpsvr_i;
+typedef std::auto_ptr<hstcpsvr_i> hstcpsvr_ptr;
+
+struct hstcpsvr_i {
+ virtual ~hstcpsvr_i() { }
+ virtual std::string start_listen() = 0;
+ static hstcpsvr_ptr create(const config& conf);
+};
+
+};
+
+#endif
+
diff --git a/plugin/handler_socket/handlersocket/hstcpsvr_worker.cpp b/plugin/handler_socket/handlersocket/hstcpsvr_worker.cpp
new file mode 100644
index 00000000..9863602a
--- /dev/null
+++ b/plugin/handler_socket/handlersocket/hstcpsvr_worker.cpp
@@ -0,0 +1,957 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#include <my_global.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <poll.h>
+#include <unistd.h>
+#include <stdexcept>
+#include <signal.h>
+#include <list>
+#if __linux__
+#include <sys/epoll.h>
+#endif
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+
+#include "hstcpsvr_worker.hpp"
+#include "string_buffer.hpp"
+#include "auto_ptrcontainer.hpp"
+#include "string_util.hpp"
+#include "escape.hpp"
+
+#define DBG_FD(x)
+#define DBG_TR(x)
+#define DBG_EP(x)
+#define DBG_MULTI(x)
+
+/* TODO */
+#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(MSG_NOSIGNAL)
+#define MSG_NOSIGNAL 0
+#endif
+
+namespace dena {
+
+struct dbconnstate {
+ string_buffer readbuf;
+ string_buffer writebuf;
+ std::vector<prep_stmt> prep_stmts;
+ size_t resp_begin_pos;
+ size_t find_nl_pos;
+ void reset() {
+ readbuf.clear();
+ writebuf.clear();
+ prep_stmts.clear();
+ resp_begin_pos = 0;
+ find_nl_pos = 0;
+ }
+ dbconnstate() : resp_begin_pos(0), find_nl_pos(0) { }
+};
+
+struct hstcpsvr_conn;
+typedef auto_ptrcontainer< std::list<hstcpsvr_conn *> > hstcpsvr_conns_type;
+
+struct hstcpsvr_conn : public dbcallback_i {
+ public:
+ auto_file fd;
+ sockaddr_storage addr;
+ size_socket addr_len;
+ dbconnstate cstate;
+ std::string err;
+ size_t readsize;
+ bool nonblocking;
+ bool read_finished;
+ bool write_finished;
+ time_t nb_last_io;
+ hstcpsvr_conns_type::iterator conns_iter;
+ bool authorized;
+ public:
+ bool closed() const;
+ bool ok_to_close() const;
+ void reset();
+ int accept(const hstcpsvr_shared_c& cshared);
+ bool write_more(bool *more_r = 0);
+ bool read_more(bool *more_r = 0);
+ public:
+ virtual void dbcb_set_prep_stmt(size_t pst_id, const prep_stmt& v);
+ virtual const prep_stmt *dbcb_get_prep_stmt(size_t pst_id) const;
+ virtual void dbcb_resp_short(uint32_t code, const char *msg);
+ virtual void dbcb_resp_short_num(uint32_t code, uint32_t value);
+ virtual void dbcb_resp_short_num64(uint32_t code, uint64_t value);
+ virtual void dbcb_resp_begin(size_t num_flds);
+ virtual void dbcb_resp_entry(const char *fld, size_t fldlen);
+ virtual void dbcb_resp_end();
+ virtual void dbcb_resp_cancel();
+ public:
+ hstcpsvr_conn() : addr_len(sizeof(addr)), readsize(4096),
+ nonblocking(false), read_finished(false), write_finished(false),
+ nb_last_io(0), authorized(false) { }
+};
+
+bool
+hstcpsvr_conn::closed() const
+{
+ return fd.get() < 0;
+}
+
+bool
+hstcpsvr_conn::ok_to_close() const
+{
+ return write_finished || (read_finished && cstate.writebuf.size() == 0);
+}
+
+void
+hstcpsvr_conn::reset()
+{
+ addr = sockaddr_storage();
+ addr_len = sizeof(addr);
+ cstate.reset();
+ fd.reset();
+ read_finished = false;
+ write_finished = false;
+}
+
+int
+hstcpsvr_conn::accept(const hstcpsvr_shared_c& cshared)
+{
+ reset();
+ return socket_accept(cshared.listen_fd.get(), fd, cshared.sockargs, addr,
+ addr_len, err);
+}
+
+bool
+hstcpsvr_conn::write_more(bool *more_r)
+{
+ if (write_finished || cstate.writebuf.size() == 0) {
+ return false;
+ }
+ const size_t wlen = cstate.writebuf.size();
+ ssize_t len = send(fd.get(), cstate.writebuf.begin(), wlen, MSG_NOSIGNAL);
+ if (len <= 0) {
+ if (len == 0 || !nonblocking || errno != EWOULDBLOCK) {
+ cstate.writebuf.clear();
+ write_finished = true;
+ }
+ return false;
+ }
+ cstate.writebuf.erase_front(len);
+ /* FIXME: reallocate memory if too large */
+ if (more_r) {
+ *more_r = (static_cast<size_t>(len) == wlen);
+ }
+ return true;
+}
+
+bool
+hstcpsvr_conn::read_more(bool *more_r)
+{
+ if (read_finished) {
+ return false;
+ }
+ const size_t block_size = readsize > 4096 ? readsize : 4096;
+ char *wp = cstate.readbuf.make_space(block_size);
+ const ssize_t len = read(fd.get(), wp, block_size);
+ if (len <= 0) {
+ if (len == 0 || !nonblocking || errno != EWOULDBLOCK) {
+ read_finished = true;
+ }
+ return false;
+ }
+ cstate.readbuf.space_wrote(len);
+ if (more_r) {
+ *more_r = (static_cast<size_t>(len) == block_size);
+ }
+ return true;
+}
+
+void
+hstcpsvr_conn::dbcb_set_prep_stmt(size_t pst_id, const prep_stmt& v)
+{
+ if (cstate.prep_stmts.size() <= pst_id) {
+ cstate.prep_stmts.resize(pst_id + 1);
+ }
+ cstate.prep_stmts[pst_id] = v;
+}
+
+const prep_stmt *
+hstcpsvr_conn::dbcb_get_prep_stmt(size_t pst_id) const
+{
+ if (cstate.prep_stmts.size() <= pst_id) {
+ return 0;
+ }
+ return &cstate.prep_stmts[pst_id];
+}
+
+void
+hstcpsvr_conn::dbcb_resp_short(uint32_t code, const char *msg)
+{
+ write_ui32(cstate.writebuf, code);
+ const size_t msglen = strlen(msg);
+ if (msglen != 0) {
+ cstate.writebuf.append_literal("\t1\t");
+ cstate.writebuf.append(msg, msg + msglen);
+ } else {
+ cstate.writebuf.append_literal("\t1");
+ }
+ cstate.writebuf.append_literal("\n");
+}
+
+void
+hstcpsvr_conn::dbcb_resp_short_num(uint32_t code, uint32_t value)
+{
+ write_ui32(cstate.writebuf, code);
+ cstate.writebuf.append_literal("\t1\t");
+ write_ui32(cstate.writebuf, value);
+ cstate.writebuf.append_literal("\n");
+}
+
+void
+hstcpsvr_conn::dbcb_resp_short_num64(uint32_t code, uint64_t value)
+{
+ write_ui32(cstate.writebuf, code);
+ cstate.writebuf.append_literal("\t1\t");
+ write_ui64(cstate.writebuf, value);
+ cstate.writebuf.append_literal("\n");
+}
+
+void
+hstcpsvr_conn::dbcb_resp_begin(size_t num_flds)
+{
+ cstate.resp_begin_pos = cstate.writebuf.size();
+ cstate.writebuf.append_literal("0\t");
+ write_ui32(cstate.writebuf, num_flds);
+}
+
+void
+hstcpsvr_conn::dbcb_resp_entry(const char *fld, size_t fldlen)
+{
+ if (fld != 0) {
+ cstate.writebuf.append_literal("\t");
+ escape_string(cstate.writebuf, fld, fld + fldlen);
+ } else {
+ static const char t[] = "\t\0";
+ cstate.writebuf.append(t, t + 2);
+ }
+}
+
+void
+hstcpsvr_conn::dbcb_resp_end()
+{
+ cstate.writebuf.append_literal("\n");
+ cstate.resp_begin_pos = 0;
+}
+
+void
+hstcpsvr_conn::dbcb_resp_cancel()
+{
+ cstate.writebuf.resize(cstate.resp_begin_pos);
+ cstate.resp_begin_pos = 0;
+}
+
+struct hstcpsvr_worker : public hstcpsvr_worker_i, private noncopyable {
+ hstcpsvr_worker(const hstcpsvr_worker_arg& arg);
+ virtual void run();
+ private:
+ const hstcpsvr_shared_c& cshared;
+ volatile hstcpsvr_shared_v& vshared;
+ long worker_id;
+ dbcontext_ptr dbctx;
+ hstcpsvr_conns_type conns; /* conns refs dbctx */
+ time_t last_check_time;
+ std::vector<pollfd> pfds;
+ #ifdef __linux__
+ std::vector<epoll_event> events_vec;
+ auto_file epoll_fd;
+ #endif
+ bool accept_enabled;
+ int accept_balance;
+ std::vector<string_ref> invalues_work;
+ std::vector<record_filter> filters_work;
+ private:
+ int run_one_nb();
+ int run_one_ep();
+ void execute_lines(hstcpsvr_conn& conn);
+ void execute_line(char *start, char *finish, hstcpsvr_conn& conn);
+ void do_open_index(char *start, char *finish, hstcpsvr_conn& conn);
+ void do_exec_on_index(char *cmd_begin, char *cmd_end, char *start,
+ char *finish, hstcpsvr_conn& conn);
+ void do_authorization(char *start, char *finish, hstcpsvr_conn& conn);
+};
+
+hstcpsvr_worker::hstcpsvr_worker(const hstcpsvr_worker_arg& arg)
+ : cshared(*arg.cshared), vshared(*arg.vshared), worker_id(arg.worker_id),
+ dbctx(cshared.dbptr->create_context(cshared.for_write_flag)),
+ last_check_time(time(0)), accept_enabled(true), accept_balance(0)
+{
+ #ifdef __linux__
+ if (cshared.sockargs.use_epoll) {
+ epoll_fd.reset(epoll_create(10));
+ if (epoll_fd.get() < 0) {
+ fatal_abort("epoll_create");
+ }
+ epoll_event ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.events = EPOLLIN;
+ ev.data.ptr = 0;
+ if (epoll_ctl(epoll_fd.get(), EPOLL_CTL_ADD, cshared.listen_fd.get(), &ev)
+ != 0) {
+ fatal_abort("epoll_ctl EPOLL_CTL_ADD");
+ }
+ events_vec.resize(10240);
+ }
+ #endif
+ accept_balance = cshared.conf.get_int("accept_balance", 0);
+}
+
+namespace {
+
+struct thr_init {
+ thr_init(const dbcontext_ptr& dc, volatile int& shutdown_flag) : dbctx(dc) {
+ dbctx->init_thread(this, shutdown_flag);
+ }
+ ~thr_init() {
+ dbctx->term_thread();
+ }
+ const dbcontext_ptr& dbctx;
+};
+
+}; // namespace
+
+void
+hstcpsvr_worker::run()
+{
+ thr_init initobj(dbctx, vshared.shutdown);
+
+ #ifdef __linux__
+ if (cshared.sockargs.use_epoll) {
+ while (!vshared.shutdown && dbctx->check_alive()) {
+ run_one_ep();
+ }
+ } else if (cshared.sockargs.nonblocking) {
+ while (!vshared.shutdown && dbctx->check_alive()) {
+ run_one_nb();
+ }
+ } else {
+ /* UNUSED */
+ fatal_abort("run_one");
+ }
+ #else
+ while (!vshared.shutdown && dbctx->check_alive()) {
+ run_one_nb();
+ }
+ #endif
+}
+
+int
+hstcpsvr_worker::run_one_nb()
+{
+ size_t nfds = 0;
+ /* CLIENT SOCKETS */
+ for (hstcpsvr_conns_type::const_iterator i = conns.begin();
+ i != conns.end(); ++i) {
+ if (pfds.size() <= nfds) {
+ pfds.resize(nfds + 1);
+ }
+ pollfd& pfd = pfds[nfds++];
+ pfd.fd = (*i)->fd.get();
+ short ev = 0;
+ if ((*i)->cstate.writebuf.size() != 0) {
+ ev = POLLOUT;
+ } else {
+ ev = POLLIN;
+ }
+ pfd.events = pfd.revents = ev;
+ }
+ /* LISTENER */
+ {
+ const size_t cpt = cshared.nb_conn_per_thread;
+ const short ev = (cpt > nfds) ? POLLIN : 0;
+ if (pfds.size() <= nfds) {
+ pfds.resize(nfds + 1);
+ }
+ pollfd& pfd = pfds[nfds++];
+ pfd.fd = cshared.listen_fd.get();
+ pfd.events = pfd.revents = ev;
+ }
+ /* POLL */
+ const int npollev = poll(&pfds[0], nfds, 1 * 1000);
+ dbctx->set_statistics(conns.size(), npollev);
+ const time_t now = time(0);
+ size_t j = 0;
+ const short mask_in = ~POLLOUT;
+ const short mask_out = POLLOUT | POLLERR | POLLHUP | POLLNVAL;
+ /* READ */
+ for (hstcpsvr_conns_type::iterator i = conns.begin(); i != conns.end();
+ ++i, ++j) {
+ pollfd& pfd = pfds[j];
+ if ((pfd.revents & mask_in) == 0) {
+ continue;
+ }
+ hstcpsvr_conn& conn = **i;
+ if (conn.read_more()) {
+ if (conn.cstate.readbuf.size() > 0) {
+ const char ch = conn.cstate.readbuf.begin()[0];
+ if (ch == 'Q') {
+ vshared.shutdown = 1;
+ } else if (ch == '/') {
+ conn.cstate.readbuf.clear();
+ conn.cstate.find_nl_pos = 0;
+ conn.cstate.writebuf.clear();
+ conn.read_finished = true;
+ conn.write_finished = true;
+ }
+ }
+ conn.nb_last_io = now;
+ }
+ }
+ /* EXECUTE */
+ j = 0;
+ for (hstcpsvr_conns_type::iterator i = conns.begin(); i != conns.end();
+ ++i, ++j) {
+ pollfd& pfd = pfds[j];
+ if ((pfd.revents & mask_in) == 0 || (*i)->cstate.readbuf.size() == 0) {
+ continue;
+ }
+ execute_lines(**i);
+ }
+ /* COMMIT */
+ dbctx->unlock_tables_if();
+ const bool commit_error = dbctx->get_commit_error();
+ dbctx->clear_error();
+ /* WRITE/CLOSE */
+ j = 0;
+ for (hstcpsvr_conns_type::iterator i = conns.begin(); i != conns.end();
+ ++j) {
+ pollfd& pfd = pfds[j];
+ hstcpsvr_conn& conn = **i;
+ hstcpsvr_conns_type::iterator icur = i;
+ ++i;
+ if (commit_error) {
+ conn.reset();
+ continue;
+ }
+ if ((pfd.revents & (mask_out | mask_in)) != 0) {
+ if (conn.write_more()) {
+ conn.nb_last_io = now;
+ }
+ }
+ if (cshared.sockargs.timeout != 0 &&
+ conn.nb_last_io + cshared.sockargs.timeout < now) {
+ conn.reset();
+ }
+ if (conn.closed() || conn.ok_to_close()) {
+ conns.erase_ptr(icur);
+ }
+ }
+ /* ACCEPT */
+ {
+ pollfd& pfd = pfds[nfds - 1];
+ if ((pfd.revents & mask_in) != 0) {
+ std::auto_ptr<hstcpsvr_conn> c(new hstcpsvr_conn());
+ c->nonblocking = true;
+ c->readsize = cshared.readsize;
+ c->accept(cshared);
+ if (c->fd.get() >= 0) {
+ if (fcntl(c->fd.get(), F_SETFL, O_NONBLOCK) != 0) {
+ fatal_abort("F_SETFL O_NONBLOCK");
+ }
+ c->nb_last_io = now;
+ conns.push_back_ptr(c);
+ } else {
+ /* errno == 11 (EAGAIN) is not a fatal error. */
+ DENA_VERBOSE(100, fprintf(stderr,
+ "accept failed: errno=%d (not fatal)\n", errno));
+ }
+ }
+ }
+ DENA_VERBOSE(30, fprintf(stderr, "nb: %p nfds=%zu cns=%zu\n", this, nfds,
+ conns.size()));
+ if (conns.empty()) {
+ dbctx->close_tables_if();
+ }
+ dbctx->set_statistics(conns.size(), 0);
+ return 0;
+}
+
+#ifdef __linux__
+int
+hstcpsvr_worker::run_one_ep()
+{
+ epoll_event *const events = &events_vec[0];
+ const size_t num_events = events_vec.size();
+ const time_t now = time(0);
+ size_t in_count = 0, out_count = 0, accept_count = 0;
+ int nfds = epoll_wait(epoll_fd.get(), events, num_events, 1000);
+ /* READ/ACCEPT */
+ dbctx->set_statistics(conns.size(), nfds);
+ for (int i = 0; i < nfds; ++i) {
+ epoll_event& ev = events[i];
+ if ((ev.events & EPOLLIN) == 0) {
+ continue;
+ }
+ hstcpsvr_conn *const conn = static_cast<hstcpsvr_conn *>(ev.data.ptr);
+ if (conn == 0) {
+ /* listener */
+ ++accept_count;
+ DBG_EP(fprintf(stderr, "IN listener\n"));
+ std::auto_ptr<hstcpsvr_conn> c(new hstcpsvr_conn());
+ c->nonblocking = true;
+ c->readsize = cshared.readsize;
+ c->accept(cshared);
+ if (c->fd.get() >= 0) {
+ if (fcntl(c->fd.get(), F_SETFL, O_NONBLOCK) != 0) {
+ fatal_abort("F_SETFL O_NONBLOCK");
+ }
+ epoll_event cev;
+ memset(&cev, 0, sizeof(cev));
+ cev.events = EPOLLIN | EPOLLOUT | EPOLLET;
+ cev.data.ptr = c.get();
+ c->nb_last_io = now;
+ const int fd = c->fd.get();
+ conns.push_back_ptr(c);
+ conns.back()->conns_iter = --conns.end();
+ if (epoll_ctl(epoll_fd.get(), EPOLL_CTL_ADD, fd, &cev) != 0) {
+ fatal_abort("epoll_ctl EPOLL_CTL_ADD");
+ }
+ } else {
+ DENA_VERBOSE(100, fprintf(stderr,
+ "accept failed: errno=%d (not fatal)\n", errno));
+ }
+ } else {
+ /* client connection */
+ ++in_count;
+ DBG_EP(fprintf(stderr, "IN client\n"));
+ bool more_data = false;
+ while (conn->read_more(&more_data)) {
+ DBG_EP(fprintf(stderr, "IN client read_more\n"));
+ conn->nb_last_io = now;
+ if (!more_data) {
+ break;
+ }
+ }
+ }
+ }
+ /* EXECUTE */
+ for (int i = 0; i < nfds; ++i) {
+ epoll_event& ev = events[i];
+ hstcpsvr_conn *const conn = static_cast<hstcpsvr_conn *>(ev.data.ptr);
+ if ((ev.events & EPOLLIN) == 0 || conn == 0 ||
+ conn->cstate.readbuf.size() == 0) {
+ continue;
+ }
+ const char ch = conn->cstate.readbuf.begin()[0];
+ if (ch == 'Q') {
+ vshared.shutdown = 1;
+ } else if (ch == '/') {
+ conn->cstate.readbuf.clear();
+ conn->cstate.find_nl_pos = 0;
+ conn->cstate.writebuf.clear();
+ conn->read_finished = true;
+ conn->write_finished = true;
+ } else {
+ execute_lines(*conn);
+ }
+ }
+ /* COMMIT */
+ dbctx->unlock_tables_if();
+ const bool commit_error = dbctx->get_commit_error();
+ dbctx->clear_error();
+ /* WRITE */
+ for (int i = 0; i < nfds; ++i) {
+ epoll_event& ev = events[i];
+ hstcpsvr_conn *const conn = static_cast<hstcpsvr_conn *>(ev.data.ptr);
+ if (commit_error && conn != 0) {
+ conn->reset();
+ continue;
+ }
+ if ((ev.events & EPOLLOUT) == 0) {
+ continue;
+ }
+ ++out_count;
+ if (conn == 0) {
+ /* listener */
+ DBG_EP(fprintf(stderr, "OUT listener\n"));
+ } else {
+ /* client connection */
+ DBG_EP(fprintf(stderr, "OUT client\n"));
+ bool more_data = false;
+ while (conn->write_more(&more_data)) {
+ DBG_EP(fprintf(stderr, "OUT client write_more\n"));
+ conn->nb_last_io = now;
+ if (!more_data) {
+ break;
+ }
+ }
+ }
+ }
+ /* CLOSE */
+ for (int i = 0; i < nfds; ++i) {
+ epoll_event& ev = events[i];
+ hstcpsvr_conn *const conn = static_cast<hstcpsvr_conn *>(ev.data.ptr);
+ if (conn != 0 && conn->ok_to_close()) {
+ DBG_EP(fprintf(stderr, "CLOSE close\n"));
+ conns.erase_ptr(conn->conns_iter);
+ }
+ }
+ /* TIMEOUT & cleanup */
+ if (last_check_time + 10 < now) {
+ for (hstcpsvr_conns_type::iterator i = conns.begin();
+ i != conns.end(); ) {
+ hstcpsvr_conns_type::iterator icur = i;
+ ++i;
+ if (cshared.sockargs.timeout != 0 &&
+ (*icur)->nb_last_io + cshared.sockargs.timeout < now) {
+ conns.erase_ptr((*icur)->conns_iter);
+ }
+ }
+ last_check_time = now;
+ DENA_VERBOSE(20, fprintf(stderr, "ep: %p nfds=%d cns=%zu\n", this, nfds,
+ conns.size()));
+ }
+ DENA_VERBOSE(30, fprintf(stderr, "%p in=%zu out=%zu ac=%zu, cns=%zu\n",
+ this, in_count, out_count, accept_count, conns.size()));
+ if (conns.empty()) {
+ dbctx->close_tables_if();
+ }
+ /* STATISTICS */
+ const size_t num_conns = conns.size();
+ dbctx->set_statistics(num_conns, 0);
+ /* ENABLE/DISABLE ACCEPT */
+ if (accept_balance != 0) {
+ cshared.thread_num_conns[worker_id] = num_conns;
+ size_t total_num_conns = 0;
+ for (long i = 0; i < cshared.num_threads; ++i) {
+ total_num_conns += cshared.thread_num_conns[i];
+ }
+ bool e_acc = false;
+ if (num_conns < 10 ||
+ total_num_conns * 2 > num_conns * cshared.num_threads) {
+ e_acc = true;
+ }
+ epoll_event ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.events = EPOLLIN;
+ ev.data.ptr = 0;
+ if (e_acc == accept_enabled) {
+ } else if (e_acc) {
+ if (epoll_ctl(epoll_fd.get(), EPOLL_CTL_ADD, cshared.listen_fd.get(), &ev)
+ != 0) {
+ fatal_abort("epoll_ctl EPOLL_CTL_ADD");
+ }
+ } else {
+ if (epoll_ctl(epoll_fd.get(), EPOLL_CTL_DEL, cshared.listen_fd.get(), &ev)
+ != 0) {
+ fatal_abort("epoll_ctl EPOLL_CTL_ADD");
+ }
+ }
+ accept_enabled = e_acc;
+ }
+ return 0;
+}
+#endif
+
+void
+hstcpsvr_worker::execute_lines(hstcpsvr_conn& conn)
+{
+ DBG_MULTI(int cnt = 0);
+ dbconnstate& cstate = conn.cstate;
+ char *buf_end = cstate.readbuf.end();
+ char *line_begin = cstate.readbuf.begin();
+ char *find_pos = line_begin + cstate.find_nl_pos;
+ while (true) {
+ char *const nl = memchr_char(find_pos, '\n', buf_end - find_pos);
+ if (nl == 0) {
+ break;
+ }
+ char *const lf = (line_begin != nl && nl[-1] == '\r') ? nl - 1 : nl;
+ DBG_MULTI(cnt++);
+ execute_line(line_begin, lf, conn);
+ find_pos = line_begin = nl + 1;
+ }
+ cstate.readbuf.erase_front(line_begin - cstate.readbuf.begin());
+ cstate.find_nl_pos = cstate.readbuf.size();
+ DBG_MULTI(fprintf(stderr, "cnt=%d\n", cnt));
+}
+
+void
+hstcpsvr_worker::execute_line(char *start, char *finish, hstcpsvr_conn& conn)
+{
+ /* safe to modify, safe to dereference 'finish' */
+ char *const cmd_begin = start;
+ read_token(start, finish);
+ char *const cmd_end = start;
+ skip_one(start, finish);
+ if (cmd_begin == cmd_end) {
+ return conn.dbcb_resp_short(2, "cmd");
+ }
+ if (cmd_begin + 1 == cmd_end) {
+ if (cmd_begin[0] == 'P') {
+ if (cshared.require_auth && !conn.authorized) {
+ return conn.dbcb_resp_short(3, "unauth");
+ }
+ return do_open_index(start, finish, conn);
+ }
+ if (cmd_begin[0] == 'A') {
+ return do_authorization(start, finish, conn);
+ }
+ }
+ if (cmd_begin[0] >= '0' && cmd_begin[0] <= '9') {
+ if (cshared.require_auth && !conn.authorized) {
+ return conn.dbcb_resp_short(3, "unauth");
+ }
+ return do_exec_on_index(cmd_begin, cmd_end, start, finish, conn);
+ }
+ return conn.dbcb_resp_short(2, "cmd");
+}
+
+void
+hstcpsvr_worker::do_open_index(char *start, char *finish, hstcpsvr_conn& conn)
+{
+ const size_t pst_id = read_ui32(start, finish);
+ skip_one(start, finish);
+ /* dbname */
+ char *const dbname_begin = start;
+ read_token(start, finish);
+ char *const dbname_end = start;
+ skip_one(start, finish);
+ /* tblname */
+ char *const tblname_begin = start;
+ read_token(start, finish);
+ char *const tblname_end = start;
+ skip_one(start, finish);
+ /* idxname */
+ char *const idxname_begin = start;
+ read_token(start, finish);
+ char *const idxname_end = start;
+ skip_one(start, finish);
+ /* retfields */
+ char *const retflds_begin = start;
+ read_token(start, finish);
+ char *const retflds_end = start;
+ skip_one(start, finish);
+ /* filfields */
+ char *const filflds_begin = start;
+ read_token(start, finish);
+ char *const filflds_end = start;
+ dbname_end[0] = 0;
+ tblname_end[0] = 0;
+ idxname_end[0] = 0;
+ retflds_end[0] = 0;
+ filflds_end[0] = 0;
+ cmd_open_args args;
+ args.pst_id = pst_id;
+ args.dbn = dbname_begin;
+ args.tbl = tblname_begin;
+ args.idx = idxname_begin;
+ args.retflds = retflds_begin;
+ args.filflds = filflds_begin;
+ return dbctx->cmd_open(conn, args);
+}
+
+void
+hstcpsvr_worker::do_exec_on_index(char *cmd_begin, char *cmd_end, char *start,
+ char *finish, hstcpsvr_conn& conn)
+{
+ cmd_exec_args args;
+ const size_t pst_id = read_ui32(cmd_begin, cmd_end);
+ if (pst_id >= conn.cstate.prep_stmts.size()) {
+ return conn.dbcb_resp_short(2, "stmtnum");
+ }
+ args.pst = &conn.cstate.prep_stmts[pst_id];
+ char *const op_begin = start;
+ read_token(start, finish);
+ char *const op_end = start;
+ args.op = string_ref(op_begin, op_end);
+ skip_one(start, finish);
+ const uint32_t fldnum = read_ui32(start, finish);
+ string_ref *const flds = DENA_ALLOCA_ALLOCATE(string_ref, fldnum);
+ auto_alloca_free<string_ref> flds_autofree(flds);
+ args.kvals = flds;
+ args.kvalslen = fldnum;
+ for (size_t i = 0; i < fldnum; ++i) {
+ skip_one(start, finish);
+ char *const f_begin = start;
+ read_token(start, finish);
+ char *const f_end = start;
+ if (is_null_expression(f_begin, f_end)) {
+ /* null */
+ flds[i] = string_ref();
+ } else {
+ /* non-null */
+ char *wp = f_begin;
+ unescape_string(wp, f_begin, f_end);
+ flds[i] = string_ref(f_begin, wp - f_begin);
+ }
+ }
+ skip_one(start, finish);
+ args.limit = read_ui32(start, finish);
+ skip_one(start, finish);
+ args.skip = read_ui32(start, finish);
+ if (start == finish) {
+ /* simple query */
+ return dbctx->cmd_exec(conn, args);
+ }
+ /* has more options */
+ skip_one(start, finish);
+ /* in-clause */
+ if (start[0] == '@') {
+ read_token(start, finish); /* '@' */
+ skip_one(start, finish);
+ args.invalues_keypart = read_ui32(start, finish);
+ skip_one(start, finish);
+ args.invalueslen = read_ui32(start, finish);
+ if (args.invalueslen <= 0) {
+ return conn.dbcb_resp_short(2, "invalueslen");
+ }
+ if (invalues_work.size() < args.invalueslen) {
+ invalues_work.resize(args.invalueslen);
+ }
+ args.invalues = &invalues_work[0];
+ for (uint32_t i = 0; i < args.invalueslen; ++i) {
+ skip_one(start, finish);
+ char *const invalue_begin = start;
+ read_token(start, finish);
+ char *const invalue_end = start;
+ char *wp = invalue_begin;
+ unescape_string(wp, invalue_begin, invalue_end);
+ invalues_work[i] = string_ref(invalue_begin, wp - invalue_begin);
+ }
+ skip_one(start, finish);
+ }
+ if (start == finish) {
+ /* no more options */
+ return dbctx->cmd_exec(conn, args);
+ }
+ /* filters */
+ size_t filters_count = 0;
+ while (start != finish && (start[0] == 'W' || start[0] == 'F')) {
+ char *const filter_type_begin = start;
+ read_token(start, finish);
+ char *const filter_type_end = start;
+ skip_one(start, finish);
+ char *const filter_op_begin = start;
+ read_token(start, finish);
+ char *const filter_op_end = start;
+ skip_one(start, finish);
+ const uint32_t ff_offset = read_ui32(start, finish);
+ skip_one(start, finish);
+ char *const filter_val_begin = start;
+ read_token(start, finish);
+ char *const filter_val_end = start;
+ skip_one(start, finish);
+ if (filters_work.size() <= filters_count) {
+ filters_work.resize(filters_count + 1);
+ }
+ record_filter& fi = filters_work[filters_count];
+ if (filter_type_end != filter_type_begin + 1) {
+ return conn.dbcb_resp_short(2, "filtertype");
+ }
+ fi.filter_type = (filter_type_begin[0] == 'W')
+ ? record_filter_type_break : record_filter_type_skip;
+ const uint32_t num_filflds = args.pst->get_filter_fields().size();
+ if (ff_offset >= num_filflds) {
+ return conn.dbcb_resp_short(2, "filterfld");
+ }
+ fi.op = string_ref(filter_op_begin, filter_op_end);
+ fi.ff_offset = ff_offset;
+ if (is_null_expression(filter_val_begin, filter_val_end)) {
+ /* null */
+ fi.val = string_ref();
+ } else {
+ /* non-null */
+ char *wp = filter_val_begin;
+ unescape_string(wp, filter_val_begin, filter_val_end);
+ fi.val = string_ref(filter_val_begin, wp - filter_val_begin);
+ }
+ ++filters_count;
+ }
+ if (filters_count > 0) {
+ if (filters_work.size() <= filters_count) {
+ filters_work.resize(filters_count + 1);
+ }
+ filters_work[filters_count].op = string_ref(); /* sentinel */
+ args.filters = &filters_work[0];
+ } else {
+ args.filters = 0;
+ }
+ if (start == finish) {
+ /* no modops */
+ return dbctx->cmd_exec(conn, args);
+ }
+ /* has modops */
+ char *const mod_op_begin = start;
+ read_token(start, finish);
+ char *const mod_op_end = start;
+ args.mod_op = string_ref(mod_op_begin, mod_op_end);
+ const size_t num_uvals = args.pst->get_ret_fields().size();
+ string_ref *const uflds = DENA_ALLOCA_ALLOCATE(string_ref, num_uvals);
+ auto_alloca_free<string_ref> uflds_autofree(uflds);
+ for (size_t i = 0; i < num_uvals; ++i) {
+ skip_one(start, finish);
+ char *const f_begin = start;
+ read_token(start, finish);
+ char *const f_end = start;
+ if (is_null_expression(f_begin, f_end)) {
+ /* null */
+ uflds[i] = string_ref();
+ } else {
+ /* non-null */
+ char *wp = f_begin;
+ unescape_string(wp, f_begin, f_end);
+ uflds[i] = string_ref(f_begin, wp - f_begin);
+ }
+ }
+ args.uvals = uflds;
+ return dbctx->cmd_exec(conn, args);
+}
+
+void
+hstcpsvr_worker::do_authorization(char *start, char *finish,
+ hstcpsvr_conn& conn)
+{
+ /* auth type */
+ char *const authtype_begin = start;
+ read_token(start, finish);
+ char *const authtype_end = start;
+ const size_t authtype_len = authtype_end - authtype_begin;
+ skip_one(start, finish);
+ /* key */
+ char *const key_begin = start;
+ read_token(start, finish);
+ char *const key_end = start;
+ const size_t key_len = key_end - key_begin;
+ authtype_end[0] = 0;
+ key_end[0] = 0;
+ char *wp = key_begin;
+ unescape_string(wp, key_begin, key_end);
+ if (authtype_len != 1 || authtype_begin[0] != '1') {
+ return conn.dbcb_resp_short(3, "authtype");
+ }
+ if (cshared.plain_secret.size() == key_len &&
+ memcmp(cshared.plain_secret.data(), key_begin, key_len) == 0) {
+ conn.authorized = true;
+ } else {
+ conn.authorized = false;
+ }
+ if (!conn.authorized) {
+ return conn.dbcb_resp_short(3, "unauth");
+ } else {
+ return conn.dbcb_resp_short(0, "");
+ }
+}
+
+hstcpsvr_worker_ptr
+hstcpsvr_worker_i::create(const hstcpsvr_worker_arg& arg)
+{
+ return hstcpsvr_worker_ptr(new hstcpsvr_worker(arg));
+}
+
+};
+
diff --git a/plugin/handler_socket/handlersocket/hstcpsvr_worker.hpp b/plugin/handler_socket/handlersocket/hstcpsvr_worker.hpp
new file mode 100644
index 00000000..497581c2
--- /dev/null
+++ b/plugin/handler_socket/handlersocket/hstcpsvr_worker.hpp
@@ -0,0 +1,35 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#ifndef DENA_HSTCPSVR_WORKER_HPP
+#define DENA_HSTCPSVR_WORKER_HPP
+
+#include "hstcpsvr.hpp"
+
+namespace dena {
+
+struct hstcpsvr_worker_i;
+typedef std::auto_ptr<hstcpsvr_worker_i> hstcpsvr_worker_ptr;
+
+struct hstcpsvr_worker_arg {
+ const hstcpsvr_shared_c *cshared;
+ volatile hstcpsvr_shared_v *vshared;
+ long worker_id;
+ hstcpsvr_worker_arg() : cshared(0), vshared(0), worker_id(0) { }
+};
+
+struct hstcpsvr_worker_i {
+ virtual ~hstcpsvr_worker_i() { }
+ virtual void run() = 0;
+ static hstcpsvr_worker_ptr create(const hstcpsvr_worker_arg& arg);
+};
+
+};
+
+#endif
+
diff --git a/plugin/handler_socket/handlersocket/mysql_incl.hpp b/plugin/handler_socket/handlersocket/mysql_incl.hpp
new file mode 100644
index 00000000..0d056a7e
--- /dev/null
+++ b/plugin/handler_socket/handlersocket/mysql_incl.hpp
@@ -0,0 +1,55 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#ifndef DENA_MYSQL_INCL_HPP
+#define DENA_MYSQL_INCL_HPP
+
+#ifndef HAVE_CONFIG_H
+#define HAVE_CONFIG_H
+#endif
+
+#ifndef MYSQL_DYNAMIC_PLUGIN
+#define MYSQL_DYNAMIC_PLUGIN
+#endif
+
+#define MYSQL_SERVER 1
+
+#include <my_global.h>
+#include <mysql_version.h>
+
+#if MYSQL_VERSION_ID >= 50505
+#include <my_pthread.h>
+#include <sql_priv.h>
+#include "sql_class.h"
+#include "unireg.h"
+#include "lock.h"
+#include "key.h" // key_copy()
+#include <my_global.h>
+#include <mysql/plugin.h>
+#include <transaction.h>
+#include <sql_base.h>
+// FIXME FIXME FIXME
+#define safeFree(X) my_free(X)
+#undef pthread_cond_timedwait
+#undef pthread_mutex_lock
+#undef pthread_mutex_unlock
+#define pthread_cond_timedwait mysql_cond_timedwait
+#define pthread_mutex_lock mysql_mutex_lock
+#define pthread_mutex_unlock mysql_mutex_unlock
+#define current_stmt_binlog_row_based is_current_stmt_binlog_format_row
+#define clear_current_stmt_binlog_row_based clear_current_stmt_binlog_format_row
+
+#else
+#include "mysql_priv.h"
+#endif
+
+#undef min
+#undef max
+
+#endif
+
diff --git a/plugin/handler_socket/libhsclient/COPYRIGHT.txt b/plugin/handler_socket/libhsclient/COPYRIGHT.txt
new file mode 100644
index 00000000..41dda127
--- /dev/null
+++ b/plugin/handler_socket/libhsclient/COPYRIGHT.txt
@@ -0,0 +1,27 @@
+
+ Copyright (c) 2010 DeNA Co.,Ltd.
+ 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 DeNA Co.,Ltd. nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY DeNA Co.,Ltd. "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 DeNA Co.,Ltd. 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.
+
diff --git a/plugin/handler_socket/libhsclient/Makefile.am b/plugin/handler_socket/libhsclient/Makefile.am
new file mode 100644
index 00000000..343b4186
--- /dev/null
+++ b/plugin/handler_socket/libhsclient/Makefile.am
@@ -0,0 +1,12 @@
+CXXFLAGS += -fimplicit-templates
+instdir = $(includedir)/handlersocket
+# TODO: these headers should be in dena/
+inst_HEADERS = allocator.hpp config.hpp mutex.hpp string_util.hpp \
+ auto_addrinfo.hpp escape.hpp socket.hpp thread.hpp auto_file.hpp \
+ fatal.hpp string_buffer.hpp util.hpp auto_ptrcontainer.hpp \
+ hstcpcli.hpp string_ref.hpp
+lib_LTLIBRARIES = libhsclient.la
+libhsclient_la_SOURCES = config.cpp escape.cpp fatal.cpp hstcpcli.cpp \
+ socket.cpp string_util.cpp
+libhsclient_la_CFLAGS = $(AM_CFLAGS)
+libhsclient_la_CXXFLAGS = $(AM_CXXFLAGS)
diff --git a/plugin/handler_socket/libhsclient/Makefile.plain b/plugin/handler_socket/libhsclient/Makefile.plain
new file mode 100644
index 00000000..9e6277b6
--- /dev/null
+++ b/plugin/handler_socket/libhsclient/Makefile.plain
@@ -0,0 +1,27 @@
+
+CXX = g++ -Wall -g -fno-rtti -fno-exceptions -fPIC -DPIC
+LDFLAGS =
+
+CXXFLAGS += -O3 -DNDEBUG
+
+COMMON_OBJS = config.o fatal.o socket.o string_util.o escape.o
+HSCLIENT_OBJS = $(COMMON_OBJS) hstcpcli.o
+
+all: libhsclient.a
+
+libhsclient.a: $(HSCLIENT_OBJS)
+ $(AR) rc $@ $^
+ $(AR) s $@
+
+clean:
+ rm -f *.a *.so *.o
+
+LIBDIR = $(shell \
+ if [ -e /usr/lib64/mysql ]; then echo /usr/lib64; else echo /usr/lib; fi)
+
+install: libhsclient.a
+ sudo sh -c 'cp libhsclient.a libhsclient.a.cpy && \
+ mv libhsclient.a.cpy $(LIBDIR)/libhsclient.a && \
+ mkdir -p /usr/include/handlersocket && \
+ cp -a *.hpp /usr/include/handlersocket/'
+
diff --git a/plugin/handler_socket/libhsclient/allocator.hpp b/plugin/handler_socket/libhsclient/allocator.hpp
new file mode 100644
index 00000000..dd3a28ba
--- /dev/null
+++ b/plugin/handler_socket/libhsclient/allocator.hpp
@@ -0,0 +1,64 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#ifndef DENA_ALLOCATOR_HPP
+#define DENA_ALLOCATOR_HPP
+
+#include <stdlib.h>
+#include <string.h>
+
+#if 0
+extern "C" {
+#include <tlsf.h>
+};
+#define DENA_MALLOC(x) tlsf_malloc(x)
+#define DENA_REALLOC(x, y) tlsf_realloc(x, y)
+#define DENA_FREE(x) tlsf_free(x)
+#define DENA_NEWCHAR(x) static_cast<char *>(tlsf_malloc(x))
+#define DENA_DELETE(x) tlsf_free(x)
+typedef std::allocator<int> allocator_type;
+#endif
+
+#if 1
+#define DENA_MALLOC(x) malloc(x)
+#define DENA_REALLOC(x, y) realloc(x, y)
+#define DENA_FREE(x) free(x)
+#define DENA_NEWCHAR(x) (new char[x])
+#define DENA_DELETE(x) (delete [] x)
+typedef std::allocator<int> allocator_type;
+#endif
+
+#if 1
+#define DENA_ALLOCA_ALLOCATE(typ, len) \
+ (typ *) alloca((len) * sizeof(typ))
+#define DENA_ALLOCA_FREE(x)
+#else
+#define DENA_ALLOCA_ALLOCATE(typ, len) \
+ static_cast<typ *>(malloc((len) * sizeof(typ)))
+#define DENA_ALLOCA_FREE(x) free(x)
+#endif
+
+namespace dena {
+
+template <typename T> struct auto_alloca_free {
+ auto_alloca_free(T *value) : value(value) { }
+ ~auto_alloca_free() {
+ /* no-op if alloca() is used */
+ DENA_ALLOCA_FREE(value);
+ }
+ private:
+ auto_alloca_free(const auto_alloca_free&);
+ auto_alloca_free& operator =(const auto_alloca_free&);
+ private:
+ T *value;
+};
+
+};
+
+#endif
+
diff --git a/plugin/handler_socket/libhsclient/auto_addrinfo.hpp b/plugin/handler_socket/libhsclient/auto_addrinfo.hpp
new file mode 100644
index 00000000..f9db70fe
--- /dev/null
+++ b/plugin/handler_socket/libhsclient/auto_addrinfo.hpp
@@ -0,0 +1,52 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#ifndef DENA_AUTO_ADDRINFO_HPP
+#define DENA_AUTO_ADDRINFO_HPP
+
+#include <my_global.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <string.h>
+#include "util.hpp"
+
+typedef SOCKET_SIZE_TYPE size_socket;
+
+namespace dena {
+
+struct auto_addrinfo : private noncopyable {
+ auto_addrinfo() : addr(0) { }
+ ~auto_addrinfo() {
+ reset();
+ }
+ void reset(addrinfo *a = 0) {
+ if (addr != 0) {
+ freeaddrinfo(addr);
+ }
+ addr = a;
+ }
+ const addrinfo *get() const { return addr; }
+ int resolve(const char *node, const char *service, int flags = 0,
+ int family = AF_UNSPEC, int socktype = SOCK_STREAM, int protocol = 0) {
+ addrinfo hints;
+ reset();
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = flags;
+ hints.ai_family = family;
+ hints.ai_socktype = socktype;
+ hints.ai_protocol = protocol;
+ return getaddrinfo(node, service, &hints, &addr);
+ }
+ private:
+ addrinfo *addr;
+};
+
+};
+
+#endif
+
diff --git a/plugin/handler_socket/libhsclient/auto_file.hpp b/plugin/handler_socket/libhsclient/auto_file.hpp
new file mode 100644
index 00000000..03c357f4
--- /dev/null
+++ b/plugin/handler_socket/libhsclient/auto_file.hpp
@@ -0,0 +1,69 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#ifndef DENA_AUTO_FILE_HPP
+#define DENA_AUTO_FILE_HPP
+
+/* Workaround for _LARGE_FILES and _LARGE_FILE_API incompatibility on AIX */
+#if defined(_AIX) && defined(_LARGE_FILE_API)
+#undef _LARGE_FILE_API
+#endif
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdio.h>
+
+#include "util.hpp"
+
+namespace dena {
+
+struct auto_file : private noncopyable {
+ auto_file() : fd(-1) { }
+ ~auto_file() {
+ reset();
+ }
+ int get() const { return fd; }
+ int close() {
+ if (fd < 0) {
+ return 0;
+ }
+ const int r = ::close(fd);
+ fd = -1;
+ return r;
+ }
+ void reset(int x = -1) {
+ if (fd >= 0) {
+ this->close();
+ }
+ fd = x;
+ }
+ private:
+ int fd;
+};
+
+struct auto_dir : private noncopyable {
+ auto_dir() : dp(0) { }
+ ~auto_dir() {
+ reset();
+ }
+ DIR *get() const { return dp; }
+ void reset(DIR *d = 0) {
+ if (dp != 0) {
+ closedir(dp);
+ }
+ dp = d;
+ }
+ private:
+ DIR *dp;
+};
+
+};
+
+#endif
+
diff --git a/plugin/handler_socket/libhsclient/auto_ptrcontainer.hpp b/plugin/handler_socket/libhsclient/auto_ptrcontainer.hpp
new file mode 100644
index 00000000..314bc151
--- /dev/null
+++ b/plugin/handler_socket/libhsclient/auto_ptrcontainer.hpp
@@ -0,0 +1,67 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#ifndef DENA_AUTO_PTRCONTAINER_HPP
+#define DENA_AUTO_PTRCONTAINER_HPP
+
+namespace dena {
+
+template <typename Tcnt>
+struct auto_ptrcontainer {
+ typedef Tcnt container_type;
+ typedef typename container_type::value_type value_type;
+ typedef typename container_type::pointer pointer;
+ typedef typename container_type::reference reference;
+ typedef typename container_type::const_reference const_reference;
+ typedef typename container_type::size_type size_type;
+ typedef typename container_type::difference_type difference_type;
+ typedef typename container_type::iterator iterator;
+ typedef typename container_type::const_iterator const_iterator;
+ typedef typename container_type::reverse_iterator reverse_iterator;
+ typedef typename container_type::const_reverse_iterator
+ const_reverse_iterator;
+ iterator begin() { return cnt.begin(); }
+ const_iterator begin() const { return cnt.begin(); }
+ iterator end() { return cnt.end(); }
+ const_iterator end() const { return cnt.end(); }
+ reverse_iterator rbegin() { return cnt.rbegin(); }
+ reverse_iterator rend() { return cnt.rend(); }
+ const_reverse_iterator rbegin() const { return cnt.rbegin(); }
+ const_reverse_iterator rend() const { return cnt.rend(); }
+ size_type size() const { return cnt.size(); }
+ size_type max_size() const { return cnt.max_size(); }
+ bool empty() const { return cnt.empty(); }
+ reference front() { return cnt.front(); }
+ const_reference front() const { cnt.front(); }
+ reference back() { return cnt.back(); }
+ const_reference back() const { cnt.back(); }
+ void swap(auto_ptrcontainer& x) { cnt.swap(x.cnt); }
+ ~auto_ptrcontainer() {
+ for (iterator i = begin(); i != end(); ++i) {
+ delete *i;
+ }
+ }
+ template <typename Tap> void push_back_ptr(Tap& ap) {
+ cnt.push_back(ap.get());
+ ap.release();
+ }
+ void erase_ptr(iterator i) {
+ delete *i;
+ cnt.erase(i);
+ }
+ reference operator [](size_type n) { return cnt[n]; }
+ const_reference operator [](size_type n) const { return cnt[n]; }
+ void clear() { cnt.clear(); }
+ private:
+ Tcnt cnt;
+};
+
+};
+
+#endif
+
diff --git a/plugin/handler_socket/libhsclient/config.cpp b/plugin/handler_socket/libhsclient/config.cpp
new file mode 100644
index 00000000..3c90b36d
--- /dev/null
+++ b/plugin/handler_socket/libhsclient/config.cpp
@@ -0,0 +1,67 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "config.hpp"
+
+namespace dena {
+
+unsigned int verbose_level = 0;
+
+std::string
+config::get_str(const std::string& key, const std::string& def) const
+{
+ const_iterator iter = this->find(key);
+ if (iter == this->end()) {
+ DENA_VERBOSE(10, fprintf(stderr, "CONFIG: %s=%s(default)\n", key.c_str(),
+ def.c_str()));
+ return def;
+ }
+ DENA_VERBOSE(10, fprintf(stderr, "CONFIG: %s=%s\n", key.c_str(),
+ iter->second.c_str()));
+ return iter->second;
+}
+
+long long
+config::get_int(const std::string& key, long long def) const
+{
+ const_iterator iter = this->find(key);
+ if (iter == this->end()) {
+ DENA_VERBOSE(10, fprintf(stderr, "CONFIG: %s=%lld(default)\n", key.c_str(),
+ def));
+ return def;
+ }
+ const long long r = atoll(iter->second.c_str());
+ DENA_VERBOSE(10, fprintf(stderr, "CONFIG: %s=%lld\n", key.c_str(), r));
+ return r;
+}
+
+void
+parse_args(int argc, char **argv, config& conf)
+{
+ for (int i = 1; i < argc; ++i) {
+ const char *const arg = argv[i];
+ const char *const eq = strchr(arg, '=');
+ if (eq == 0) {
+ continue;
+ }
+ const std::string key(arg, eq - arg);
+ const std::string val(eq + 1);
+ conf[key] = val;
+ }
+ config::const_iterator iter = conf.find("verbose");
+ if (iter != conf.end()) {
+ verbose_level = atoi(iter->second.c_str());
+ }
+}
+
+};
+
diff --git a/plugin/handler_socket/libhsclient/config.hpp b/plugin/handler_socket/libhsclient/config.hpp
new file mode 100644
index 00000000..c9f16c76
--- /dev/null
+++ b/plugin/handler_socket/libhsclient/config.hpp
@@ -0,0 +1,32 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#ifndef DENA_CONFIG_HPP
+#define DENA_CONFIG_HPP
+
+#include <string>
+#include <map>
+
+#define DENA_VERBOSE(lv, x) if (dena::verbose_level >= (lv)) { (x); }
+
+namespace dena {
+
+struct config : public std::map<std::string, std::string> {
+ std::string get_str(const std::string& key, const std::string& def = "")
+ const;
+ long long get_int(const std::string& key, long long def = 0) const;
+};
+
+void parse_args(int argc, char **argv, config& conf);
+
+extern unsigned int verbose_level;
+
+};
+
+#endif
+
diff --git a/plugin/handler_socket/libhsclient/escape.cpp b/plugin/handler_socket/libhsclient/escape.cpp
new file mode 100644
index 00000000..d4df8ae8
--- /dev/null
+++ b/plugin/handler_socket/libhsclient/escape.cpp
@@ -0,0 +1,127 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#include <stdio.h>
+
+#include "escape.hpp"
+#include "string_buffer.hpp"
+#include "fatal.hpp"
+#include "string_util.hpp"
+
+#define DBG_OP(x)
+#define DBG_BUF(x)
+
+namespace dena {
+
+enum special_char_t {
+ special_char_escape_prefix = 0x01, /* SOH */
+ special_char_noescape_min = 0x10, /* DLE */
+ special_char_escape_shift = 0x40, /* '@' */
+};
+
+void
+escape_string(char *& wp, const char *start, const char *finish)
+{
+ while (start != finish) {
+ const unsigned char c = *start;
+ if (c >= special_char_noescape_min) {
+ wp[0] = c; /* no need to escape */
+ } else {
+ wp[0] = special_char_escape_prefix;
+ ++wp;
+ wp[0] = c + special_char_escape_shift;
+ }
+ ++start;
+ ++wp;
+ }
+}
+
+void
+escape_string(string_buffer& ar, const char *start, const char *finish)
+{
+ const size_t buflen = (finish - start) * 2;
+ char *const wp_begin = ar.make_space(buflen);
+ char *wp = wp_begin;
+ escape_string(wp, start, finish);
+ ar.space_wrote(wp - wp_begin);
+}
+
+bool
+unescape_string(char *& wp, const char *start, const char *finish)
+{
+ /* works even if wp == start */
+ while (start != finish) {
+ const unsigned char c = *start;
+ if (c != special_char_escape_prefix) {
+ wp[0] = c;
+ } else if (start + 1 != finish) {
+ ++start;
+ const unsigned char cn = *start;
+ if (cn < special_char_escape_shift) {
+ return false;
+ }
+ wp[0] = cn - special_char_escape_shift;
+ } else {
+ return false;
+ }
+ ++start;
+ ++wp;
+ }
+ return true;
+}
+
+bool
+unescape_string(string_buffer& ar, const char *start, const char *finish)
+{
+ const size_t buflen = finish - start;
+ char *const wp_begin = ar.make_space(buflen);
+ char *wp = wp_begin;
+ const bool r = unescape_string(wp, start, finish);
+ ar.space_wrote(wp - wp_begin);
+ return r;
+}
+
+uint32_t
+read_ui32(char *& start, char *finish)
+{
+ char *const n_begin = start;
+ read_token(start, finish);
+ char *const n_end = start;
+ uint32_t v = 0;
+ for (char *p = n_begin; p != n_end; ++p) {
+ const char ch = p[0];
+ if (ch >= '0' && ch <= '9') {
+ v *= 10;
+ v += (ch - '0');
+ }
+ }
+ return v;
+}
+
+void
+write_ui32(string_buffer& buf, uint32_t v)
+{
+ char *wp = buf.make_space(12);
+ int len = snprintf(wp, 12, "%u", v);
+ if (len > 0) {
+ buf.space_wrote(len);
+ }
+}
+
+void
+write_ui64(string_buffer& buf, uint64_t v)
+{
+ char *wp = buf.make_space(22);
+ int len = snprintf(wp, 22, "%llu", static_cast<unsigned long long>(v));
+ if (len > 0) {
+ buf.space_wrote(len);
+ }
+}
+
+};
+
diff --git a/plugin/handler_socket/libhsclient/escape.hpp b/plugin/handler_socket/libhsclient/escape.hpp
new file mode 100644
index 00000000..b928defe
--- /dev/null
+++ b/plugin/handler_socket/libhsclient/escape.hpp
@@ -0,0 +1,66 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#include <stdint.h>
+
+#include "string_buffer.hpp"
+#include "string_ref.hpp"
+#include "string_util.hpp"
+
+#ifndef DENA_ESCAPE_HPP
+#define DENA_ESCAPE_HPP
+
+namespace dena {
+
+void escape_string(char *& wp, const char *start, const char *finish);
+void escape_string(string_buffer& ar, const char *start, const char *finish);
+bool unescape_string(char *& wp, const char *start, const char *finish);
+ /* unescaped_string() works even if wp == start */
+bool unescape_string(string_buffer& ar, const char *start, const char *finish);
+
+uint32_t read_ui32(char *& start, char *finish);
+void write_ui32(string_buffer& buf, uint32_t v);
+void write_ui64(string_buffer& buf, uint64_t v);
+
+inline bool
+is_null_expression(const char *start, const char *finish)
+{
+ return (finish == start + 1 && start[0] == 0);
+}
+
+inline void
+read_token(char *& start, char *finish)
+{
+ char *const p = memchr_char(start, '\t', finish - start);
+ if (p == 0) {
+ start = finish;
+ } else {
+ start = p;
+ }
+}
+
+inline void
+skip_token_delim_fold(char *& start, char *finish)
+{
+ while (start != finish && start[0] == '\t') {
+ ++start;
+ }
+}
+
+inline void
+skip_one(char *& start, char *finish)
+{
+ if (start != finish) {
+ ++start;
+ }
+}
+
+};
+
+#endif
+
diff --git a/plugin/handler_socket/libhsclient/fatal.cpp b/plugin/handler_socket/libhsclient/fatal.cpp
new file mode 100644
index 00000000..8e109cf1
--- /dev/null
+++ b/plugin/handler_socket/libhsclient/fatal.cpp
@@ -0,0 +1,29 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "fatal.hpp"
+
+namespace dena {
+
+const int opt_syslog = LOG_ERR | LOG_PID | LOG_CONS;
+
+void
+fatal_abort(const std::string& message)
+{
+ fprintf(stderr, "FATAL_COREDUMP: %s\n", message.c_str());
+ syslog(opt_syslog, "FATAL_COREDUMP: %s", message.c_str());
+ abort();
+}
+
+};
+
diff --git a/plugin/handler_socket/libhsclient/fatal.hpp b/plugin/handler_socket/libhsclient/fatal.hpp
new file mode 100644
index 00000000..5eaa3db8
--- /dev/null
+++ b/plugin/handler_socket/libhsclient/fatal.hpp
@@ -0,0 +1,21 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#ifndef DENA_FATAL_HPP
+#define DENA_FATAL_HPP
+
+#include <string>
+
+namespace dena {
+
+void fatal_abort(const std::string& message);
+
+};
+
+#endif
+
diff --git a/plugin/handler_socket/libhsclient/hstcpcli.cpp b/plugin/handler_socket/libhsclient/hstcpcli.cpp
new file mode 100644
index 00000000..461bed3f
--- /dev/null
+++ b/plugin/handler_socket/libhsclient/hstcpcli.cpp
@@ -0,0 +1,442 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#include <my_global.h>
+#include <stdexcept>
+
+#include "hstcpcli.hpp"
+#include "auto_file.hpp"
+#include "string_util.hpp"
+#include "auto_addrinfo.hpp"
+#include "escape.hpp"
+#include "util.hpp"
+
+/* TODO */
+#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(MSG_NOSIGNAL)
+#define MSG_NOSIGNAL 0
+#endif
+
+#define DBG(x)
+
+namespace dena {
+
+struct hstcpcli : public hstcpcli_i, private noncopyable {
+ hstcpcli(const socket_args& args);
+ virtual void close();
+ virtual int reconnect();
+ virtual bool stable_point();
+ virtual void request_buf_open_index(size_t pst_id, const char *dbn,
+ const char *tbl, const char *idx, const char *retflds, const char *filflds);
+ virtual void request_buf_auth(const char *secret, const char *typ);
+ virtual void request_buf_exec_generic(size_t pst_id, const string_ref& op,
+ const string_ref *kvs, size_t kvslen, uint32_t limit, uint32_t skip,
+ const string_ref& mod_op, const string_ref *mvs, size_t mvslen,
+ const hstcpcli_filter *fils, size_t filslen, int invalues_keypart,
+ const string_ref *invalues, size_t invalueslen);
+ virtual int request_send();
+ virtual int response_recv(size_t& num_flds_r);
+ virtual const string_ref *get_next_row();
+ virtual void response_buf_remove();
+ virtual int get_error_code();
+ virtual std::string get_error();
+ private:
+ int read_more();
+ void clear_error();
+ int set_error(int code, const std::string& str);
+ private:
+ auto_file fd;
+ socket_args sargs;
+ string_buffer readbuf;
+ string_buffer writebuf;
+ size_t response_end_offset; /* incl newline */
+ size_t cur_row_offset;
+ size_t num_flds;
+ size_t num_req_bufd; /* buffered but not yet sent */
+ size_t num_req_sent; /* sent but not yet received */
+ size_t num_req_rcvd; /* received but not yet removed */
+ int error_code;
+ std::string error_str;
+ std::vector<string_ref> flds;
+};
+
+hstcpcli::hstcpcli(const socket_args& args)
+ : sargs(args), response_end_offset(0), cur_row_offset(0), num_flds(0),
+ num_req_bufd(0), num_req_sent(0), num_req_rcvd(0), error_code(0)
+{
+ std::string err;
+ if (socket_connect(fd, sargs, err) != 0) {
+ set_error(-1, err);
+ }
+}
+
+void
+hstcpcli::close()
+{
+ fd.close();
+ readbuf.clear();
+ writebuf.clear();
+ flds.clear();
+ response_end_offset = 0;
+ cur_row_offset = 0;
+ num_flds = 0;
+ num_req_bufd = 0;
+ num_req_sent = 0;
+ num_req_rcvd = 0;
+}
+
+int
+hstcpcli::reconnect()
+{
+ clear_error();
+ close();
+ std::string err;
+ if (socket_connect(fd, sargs, err) != 0) {
+ set_error(-1, err);
+ }
+ return error_code;
+}
+
+bool
+hstcpcli::stable_point()
+{
+ /* returns true if cli can send a new request */
+ return fd.get() >= 0 && num_req_bufd == 0 && num_req_sent == 0 &&
+ num_req_rcvd == 0 && response_end_offset == 0;
+}
+
+int
+hstcpcli::get_error_code()
+{
+ return error_code;
+}
+
+std::string
+hstcpcli::get_error()
+{
+ return error_str;
+}
+
+int
+hstcpcli::read_more()
+{
+ const size_t block_size = 4096; // FIXME
+ char *const wp = readbuf.make_space(block_size);
+ const ssize_t rlen = read(fd.get(), wp, block_size);
+ if (rlen <= 0) {
+ if (rlen < 0) {
+ error_str = "read: failed";
+ } else {
+ error_str = "read: eof";
+ }
+ return rlen;
+ }
+ readbuf.space_wrote(rlen);
+ return rlen;
+}
+
+void
+hstcpcli::clear_error()
+{
+ DBG(fprintf(stderr, "CLEAR_ERROR: %d\n", error_code));
+ error_code = 0;
+ error_str.clear();
+}
+
+int
+hstcpcli::set_error(int code, const std::string& str)
+{
+ DBG(fprintf(stderr, "SET_ERROR: %d\n", code));
+ error_code = code;
+ error_str = str;
+ return error_code;
+}
+
+void
+hstcpcli::request_buf_open_index(size_t pst_id, const char *dbn,
+ const char *tbl, const char *idx, const char *retflds, const char *filflds)
+{
+ if (num_req_sent > 0 || num_req_rcvd > 0) {
+ close();
+ set_error(-1, "request_buf_open_index: protocol out of sync");
+ return;
+ }
+ const string_ref dbn_ref(dbn, strlen(dbn));
+ const string_ref tbl_ref(tbl, strlen(tbl));
+ const string_ref idx_ref(idx, strlen(idx));
+ const string_ref rfs_ref(retflds, strlen(retflds));
+ writebuf.append_literal("P\t");
+ append_uint32(writebuf, pst_id); // FIXME size_t ?
+ writebuf.append_literal("\t");
+ writebuf.append(dbn_ref.begin(), dbn_ref.end());
+ writebuf.append_literal("\t");
+ writebuf.append(tbl_ref.begin(), tbl_ref.end());
+ writebuf.append_literal("\t");
+ writebuf.append(idx_ref.begin(), idx_ref.end());
+ writebuf.append_literal("\t");
+ writebuf.append(rfs_ref.begin(), rfs_ref.end());
+ if (filflds != 0) {
+ const string_ref fls_ref(filflds, strlen(filflds));
+ writebuf.append_literal("\t");
+ writebuf.append(fls_ref.begin(), fls_ref.end());
+ }
+ writebuf.append_literal("\n");
+ ++num_req_bufd;
+}
+
+void
+hstcpcli::request_buf_auth(const char *secret, const char *typ)
+{
+ if (num_req_sent > 0 || num_req_rcvd > 0) {
+ close();
+ set_error(-1, "request_buf_auth: protocol out of sync");
+ return;
+ }
+ if (typ == 0) {
+ typ = "1";
+ }
+ const string_ref typ_ref(typ, strlen(typ));
+ const string_ref secret_ref(secret, strlen(secret));
+ writebuf.append_literal("A\t");
+ writebuf.append(typ_ref.begin(), typ_ref.end());
+ writebuf.append_literal("\t");
+ writebuf.append(secret_ref.begin(), secret_ref.end());
+ writebuf.append_literal("\n");
+ ++num_req_bufd;
+}
+
+namespace {
+
+void
+append_delim_value(string_buffer& buf, const char *start, const char *finish)
+{
+ if (start == 0) {
+ /* null */
+ const char t[] = "\t\0";
+ buf.append(t, t + 2);
+ } else {
+ /* non-null */
+ buf.append_literal("\t");
+ escape_string(buf, start, finish);
+ }
+}
+
+};
+
+void
+hstcpcli::request_buf_exec_generic(size_t pst_id, const string_ref& op,
+ const string_ref *kvs, size_t kvslen, uint32_t limit, uint32_t skip,
+ const string_ref& mod_op, const string_ref *mvs, size_t mvslen,
+ const hstcpcli_filter *fils, size_t filslen, int invalues_keypart,
+ const string_ref *invalues, size_t invalueslen)
+{
+ if (num_req_sent > 0 || num_req_rcvd > 0) {
+ close();
+ set_error(-1, "request_buf_exec_generic: protocol out of sync");
+ return;
+ }
+ append_uint32(writebuf, pst_id); // FIXME size_t ?
+ writebuf.append_literal("\t");
+ writebuf.append(op.begin(), op.end());
+ writebuf.append_literal("\t");
+ append_uint32(writebuf, kvslen); // FIXME size_t ?
+ for (size_t i = 0; i < kvslen; ++i) {
+ const string_ref& kv = kvs[i];
+ append_delim_value(writebuf, kv.begin(), kv.end());
+ }
+ if (limit != 0 || skip != 0 || invalues_keypart >= 0 ||
+ mod_op.size() != 0 || filslen != 0) {
+ /* has more option */
+ writebuf.append_literal("\t");
+ append_uint32(writebuf, limit); // FIXME size_t ?
+ if (skip != 0 || invalues_keypart >= 0 ||
+ mod_op.size() != 0 || filslen != 0) {
+ writebuf.append_literal("\t");
+ append_uint32(writebuf, skip); // FIXME size_t ?
+ }
+ if (invalues_keypart >= 0) {
+ writebuf.append_literal("\t@\t");
+ append_uint32(writebuf, invalues_keypart);
+ writebuf.append_literal("\t");
+ append_uint32(writebuf, invalueslen);
+ for (size_t i = 0; i < invalueslen; ++i) {
+ const string_ref& s = invalues[i];
+ append_delim_value(writebuf, s.begin(), s.end());
+ }
+ }
+ for (size_t i = 0; i < filslen; ++i) {
+ const hstcpcli_filter& f = fils[i];
+ writebuf.append_literal("\t");
+ writebuf.append(f.filter_type.begin(), f.filter_type.end());
+ writebuf.append_literal("\t");
+ writebuf.append(f.op.begin(), f.op.end());
+ writebuf.append_literal("\t");
+ append_uint32(writebuf, f.ff_offset);
+ append_delim_value(writebuf, f.val.begin(), f.val.end());
+ }
+ if (mod_op.size() != 0) {
+ writebuf.append_literal("\t");
+ writebuf.append(mod_op.begin(), mod_op.end());
+ for (size_t i = 0; i < mvslen; ++i) {
+ const string_ref& mv = mvs[i];
+ append_delim_value(writebuf, mv.begin(), mv.end());
+ }
+ }
+ }
+ writebuf.append_literal("\n");
+ ++num_req_bufd;
+}
+
+int
+hstcpcli::request_send()
+{
+ if (error_code < 0) {
+ return error_code;
+ }
+ clear_error();
+ if (fd.get() < 0) {
+ close();
+ return set_error(-1, "write: closed");
+ }
+ if (num_req_bufd == 0 || num_req_sent > 0 || num_req_rcvd > 0) {
+ close();
+ return set_error(-1, "request_send: protocol out of sync");
+ }
+ const size_t wrlen = writebuf.size();
+ const ssize_t r = send(fd.get(), writebuf.begin(), wrlen, MSG_NOSIGNAL);
+ if (r <= 0) {
+ close();
+ return set_error(-1, r < 0 ? "write: failed" : "write: eof");
+ }
+ writebuf.erase_front(r);
+ if (static_cast<size_t>(r) != wrlen) {
+ close();
+ return set_error(-1, "write: incomplete");
+ }
+ num_req_sent = num_req_bufd;
+ num_req_bufd = 0;
+ DBG(fprintf(stderr, "REQSEND 0\n"));
+ return 0;
+}
+
+int
+hstcpcli::response_recv(size_t& num_flds_r)
+{
+ if (error_code < 0) {
+ return error_code;
+ }
+ clear_error();
+ if (num_req_bufd > 0 || num_req_sent == 0 || num_req_rcvd > 0 ||
+ response_end_offset != 0) {
+ close();
+ return set_error(-1, "response_recv: protocol out of sync");
+ }
+ cur_row_offset = 0;
+ num_flds_r = num_flds = 0;
+ if (fd.get() < 0) {
+ return set_error(-1, "read: closed");
+ }
+ size_t offset = 0;
+ while (true) {
+ const char *const lbegin = readbuf.begin() + offset;
+ const char *const lend = readbuf.end();
+ const char *const nl = memchr_char(lbegin, '\n', lend - lbegin);
+ if (nl != 0) {
+ offset = (nl + 1) - readbuf.begin();
+ break;
+ }
+ if (read_more() <= 0) {
+ close();
+ return set_error(-1, "read: eof");
+ }
+ }
+ response_end_offset = offset;
+ --num_req_sent;
+ ++num_req_rcvd;
+ char *start = readbuf.begin();
+ char *const finish = start + response_end_offset - 1;
+ const size_t resp_code = read_ui32(start, finish);
+ skip_one(start, finish);
+ num_flds_r = num_flds = read_ui32(start, finish);
+ if (resp_code != 0) {
+ skip_one(start, finish);
+ char *const err_begin = start;
+ read_token(start, finish);
+ char *const err_end = start;
+ std::string e = std::string(err_begin, err_end - err_begin);
+ if (e.empty()) {
+ e = "unknown_error";
+ }
+ return set_error(resp_code, e);
+ }
+ cur_row_offset = start - readbuf.begin();
+ DBG(fprintf(stderr, "[%s] ro=%zu eol=%zu\n",
+ std::string(readbuf.begin(), readbuf.begin() + response_end_offset)
+ .c_str(),
+ cur_row_offset, response_end_offset));
+ DBG(fprintf(stderr, "RES 0\n"));
+ return 0;
+}
+
+const string_ref *
+hstcpcli::get_next_row()
+{
+ if (num_flds == 0) {
+ DBG(fprintf(stderr, "GNR NF 0\n"));
+ return 0;
+ }
+ if (flds.size() < num_flds) {
+ flds.resize(num_flds);
+ }
+ char *start = readbuf.begin() + cur_row_offset;
+ char *const finish = readbuf.begin() + response_end_offset - 1;
+ if (start >= finish) { /* start[0] == nl */
+ DBG(fprintf(stderr, "GNR FIN 0 %p %p\n", start, finish));
+ return 0;
+ }
+ for (size_t i = 0; i < num_flds; ++i) {
+ skip_one(start, finish);
+ char *const fld_begin = start;
+ read_token(start, finish);
+ char *const fld_end = start;
+ char *wp = fld_begin;
+ if (is_null_expression(fld_begin, fld_end)) {
+ /* null */
+ flds[i] = string_ref();
+ } else {
+ unescape_string(wp, fld_begin, fld_end); /* in-place */
+ flds[i] = string_ref(fld_begin, wp);
+ }
+ }
+ cur_row_offset = start - readbuf.begin();
+ return &flds[0];
+}
+
+void
+hstcpcli::response_buf_remove()
+{
+ if (response_end_offset == 0) {
+ close();
+ set_error(-1, "response_buf_remove: protocol out of sync");
+ return;
+ }
+ readbuf.erase_front(response_end_offset);
+ response_end_offset = 0;
+ --num_req_rcvd;
+ cur_row_offset = 0;
+ num_flds = 0;
+ flds.clear();
+}
+
+hstcpcli_ptr
+hstcpcli_i::create(const socket_args& args)
+{
+ return hstcpcli_ptr(new hstcpcli(args));
+}
+
+};
+
diff --git a/plugin/handler_socket/libhsclient/hstcpcli.hpp b/plugin/handler_socket/libhsclient/hstcpcli.hpp
new file mode 100644
index 00000000..11dec8eb
--- /dev/null
+++ b/plugin/handler_socket/libhsclient/hstcpcli.hpp
@@ -0,0 +1,62 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#ifndef DENA_HSTCPCLI_HPP
+#define DENA_HSTCPCLI_HPP
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <string>
+#include <memory>
+
+#include "config.hpp"
+#include "socket.hpp"
+#include "string_ref.hpp"
+#include "string_buffer.hpp"
+
+namespace dena {
+
+struct hstcpcli_filter {
+ string_ref filter_type;
+ string_ref op;
+ size_t ff_offset;
+ string_ref val;
+ hstcpcli_filter() : ff_offset(0) { }
+};
+
+struct hstcpcli_i;
+typedef std::auto_ptr<hstcpcli_i> hstcpcli_ptr;
+
+struct hstcpcli_i {
+ virtual ~hstcpcli_i() { }
+ virtual void close() = 0;
+ virtual int reconnect() = 0;
+ virtual bool stable_point() = 0;
+ virtual void request_buf_auth(const char *secret, const char *typ) = 0;
+ virtual void request_buf_open_index(size_t pst_id, const char *dbn,
+ const char *tbl, const char *idx, const char *retflds,
+ const char *filflds = 0) = 0;
+ virtual void request_buf_exec_generic(size_t pst_id, const string_ref& op,
+ const string_ref *kvs, size_t kvslen, uint32_t limit, uint32_t skip,
+ const string_ref& mod_op, const string_ref *mvs, size_t mvslen,
+ const hstcpcli_filter *fils = 0, size_t filslen = 0,
+ int invalues_keypart = -1, const string_ref *invalues = 0,
+ size_t invalueslen = 0) = 0; // FIXME: too long
+ virtual int request_send() = 0;
+ virtual int response_recv(size_t& num_flds_r) = 0;
+ virtual const string_ref *get_next_row() = 0;
+ virtual void response_buf_remove() = 0;
+ virtual int get_error_code() = 0;
+ virtual std::string get_error() = 0;
+ static hstcpcli_ptr create(const socket_args& args);
+};
+
+};
+
+#endif
+
diff --git a/plugin/handler_socket/libhsclient/libhsclient.spec.template b/plugin/handler_socket/libhsclient/libhsclient.spec.template
new file mode 100644
index 00000000..3e4dfe04
--- /dev/null
+++ b/plugin/handler_socket/libhsclient/libhsclient.spec.template
@@ -0,0 +1,39 @@
+Summary: handlersocket client library
+Name: libhsclient
+Version: HANDLERSOCKET_VERSION
+Release: 1%{?dist}
+Group: System Environment/Libraries
+License: BSD
+Source: libhsclient.tar.gz
+Packager: Akira Higuchi <higuchi dot akira at dena dot jp>
+BuildRoot: /var/tmp/%{name}-%{version}-root
+
+%description
+
+%prep
+%setup -n %{name}
+
+%define _use_internal_dependency_generator 0
+
+%build
+make -f Makefile.plain
+
+%install
+rm -rf $RPM_BUILD_ROOT
+mkdir -p $RPM_BUILD_ROOT/usr/include/handlersocket
+mkdir -p $RPM_BUILD_ROOT/%{_bindir}
+mkdir -p $RPM_BUILD_ROOT/%{_libdir}
+install -m 755 libhsclient.a $RPM_BUILD_ROOT/%{_libdir}
+install -m 644 *.hpp $RPM_BUILD_ROOT/usr/include/handlersocket/
+
+%post
+/sbin/ldconfig
+
+%postun
+/sbin/ldconfig
+
+%files
+%defattr(-, root, root)
+/usr/include/*
+%{_libdir}/*.a
+
diff --git a/plugin/handler_socket/libhsclient/mutex.hpp b/plugin/handler_socket/libhsclient/mutex.hpp
new file mode 100644
index 00000000..9cef2757
--- /dev/null
+++ b/plugin/handler_socket/libhsclient/mutex.hpp
@@ -0,0 +1,51 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#ifndef DENA_MUTEX_HPP
+#define DENA_MUTEX_HPP
+
+#include <pthread.h>
+#include <stdlib.h>
+
+#include "fatal.hpp"
+#include "util.hpp"
+
+namespace dena {
+
+struct condition;
+
+struct mutex : private noncopyable {
+ friend struct condition;
+ mutex() {
+ if (pthread_mutex_init(&mtx, 0) != 0) {
+ fatal_abort("pthread_mutex_init");
+ }
+ }
+ ~mutex() {
+ if (pthread_mutex_destroy(&mtx) != 0) {
+ fatal_abort("pthread_mutex_destroy");
+ }
+ }
+ void lock() const {
+ if (pthread_mutex_lock(&mtx) != 0) {
+ fatal_abort("pthread_mutex_lock");
+ }
+ }
+ void unlock() const {
+ if (pthread_mutex_unlock(&mtx) != 0) {
+ fatal_abort("pthread_mutex_unlock");
+ }
+ }
+ private:
+ mutable pthread_mutex_t mtx;
+};
+
+};
+
+#endif
+
diff --git a/plugin/handler_socket/libhsclient/socket.cpp b/plugin/handler_socket/libhsclient/socket.cpp
new file mode 100644
index 00000000..f1cdc9fb
--- /dev/null
+++ b/plugin/handler_socket/libhsclient/socket.cpp
@@ -0,0 +1,185 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#include <my_global.h>
+
+#include <stdexcept>
+#include <string.h>
+#include <signal.h>
+#include <sys/un.h>
+
+#include "socket.hpp"
+#include "string_util.hpp"
+#include "fatal.hpp"
+
+namespace dena {
+
+void
+ignore_sigpipe()
+{
+ if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
+ fatal_abort("SIGPIPE SIG_IGN");
+ }
+}
+
+void
+socket_args::set(const config& conf)
+{
+ timeout = conf.get_int("timeout", 600);
+ listen_backlog = conf.get_int("listen_backlog", 256);
+ std::string node = conf.get_str("host", "");
+ std::string port = conf.get_str("port", "");
+ if (!node.empty() || !port.empty()) {
+ if (family == AF_UNIX || node == "/") {
+ set_unix_domain(port.c_str());
+ } else {
+ const char *nd = node.empty() ? 0 : node.c_str();
+ if (resolve(nd, port.c_str()) != 0) {
+ fatal_abort("getaddrinfo failed: " + node + ":" + port);
+ }
+ }
+ }
+ sndbuf = conf.get_int("sndbuf", 0);
+ rcvbuf = conf.get_int("rcvbuf", 0);
+}
+
+void
+socket_args::set_unix_domain(const char *path)
+{
+ family = AF_UNIX;
+ addr = sockaddr_storage();
+ addrlen = sizeof(sockaddr_un);
+ sockaddr_un *const ap = reinterpret_cast<sockaddr_un *>(&addr);
+ ap->sun_family = AF_UNIX;
+ strncpy(ap->sun_path, path, sizeof(ap->sun_path) - 1);
+}
+
+int
+socket_args::resolve(const char *node, const char *service)
+{
+ const int flags = (node == 0) ? AI_PASSIVE : 0;
+ auto_addrinfo ai;
+ addr = sockaddr_storage();
+ addrlen = 0;
+ const int r = ai.resolve(node, service, flags, family, socktype, protocol);
+ if (r != 0) {
+ return r;
+ }
+ memcpy(&addr, ai.get()->ai_addr, ai.get()->ai_addrlen);
+ addrlen = ai.get()->ai_addrlen;
+ return 0;
+}
+
+int
+socket_set_options(auto_file& fd, const socket_args& args, std::string& err_r)
+{
+ if (args.timeout != 0 && !args.nonblocking) {
+ struct timeval tv;
+ tv.tv_sec = args.timeout;
+ tv.tv_usec = 0;
+ if (setsockopt(fd.get(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) != 0) {
+ return errno_string("setsockopt SO_RCVTIMEO", errno, err_r);
+ }
+ tv.tv_sec = args.timeout;
+ tv.tv_usec = 0;
+ if (setsockopt(fd.get(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) != 0) {
+ return errno_string("setsockopt SO_RCVTIMEO", errno, err_r);
+ }
+ }
+ if (args.nonblocking && fcntl(fd.get(), F_SETFL, O_NONBLOCK) != 0) {
+ return errno_string("fcntl O_NONBLOCK", errno, err_r);
+ }
+ if (args.sndbuf != 0) {
+ const int v = args.sndbuf;
+ if (setsockopt(fd.get(), SOL_SOCKET, SO_SNDBUF, &v, sizeof(v)) != 0) {
+ return errno_string("setsockopt SO_SNDBUF", errno, err_r);
+ }
+ }
+ if (args.rcvbuf != 0) {
+ const int v = args.rcvbuf;
+ if (setsockopt(fd.get(), SOL_SOCKET, SO_RCVBUF, &v, sizeof(v)) != 0) {
+ return errno_string("setsockopt SO_RCVBUF", errno, err_r);
+ }
+ }
+ return 0;
+}
+
+int
+socket_open(auto_file& fd, const socket_args& args, std::string& err_r)
+{
+ fd.reset(socket(args.family, args.socktype, args.protocol));
+ if (fd.get() < 0) {
+ return errno_string("socket", errno, err_r);
+ }
+ return socket_set_options(fd, args, err_r);
+}
+
+int
+socket_connect(auto_file& fd, const socket_args& args, std::string& err_r)
+{
+ int r = 0;
+ if ((r = socket_open(fd, args, err_r)) != 0) {
+ return r;
+ }
+ if (connect(fd.get(), reinterpret_cast<const sockaddr *>(&args.addr),
+ args.addrlen) != 0) {
+ if (!args.nonblocking || errno != EINPROGRESS) {
+ return errno_string("connect", errno, err_r);
+ }
+ }
+ return 0;
+}
+
+int
+socket_bind(auto_file& fd, const socket_args& args, std::string& err_r)
+{
+ fd.reset(socket(args.family, args.socktype, args.protocol));
+ if (fd.get() < 0) {
+ return errno_string("socket", errno, err_r);
+ }
+ if (args.reuseaddr) {
+ if (args.family == AF_UNIX) {
+ const sockaddr_un *const ap =
+ reinterpret_cast<const sockaddr_un *>(&args.addr);
+ if (unlink(ap->sun_path) != 0 && errno != ENOENT) {
+ return errno_string("unlink uds", errno, err_r);
+ }
+ } else {
+ int v = 1;
+ if (setsockopt(fd.get(), SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v)) != 0) {
+ return errno_string("setsockopt SO_REUSEADDR", errno, err_r);
+ }
+ }
+ }
+ if (bind(fd.get(), reinterpret_cast<const sockaddr *>(&args.addr),
+ args.addrlen) != 0) {
+ return errno_string("bind", errno, err_r);
+ }
+ if (listen(fd.get(), args.listen_backlog) != 0) {
+ return errno_string("listen", errno, err_r);
+ }
+ if (args.nonblocking && fcntl(fd.get(), F_SETFL, O_NONBLOCK) != 0) {
+ return errno_string("fcntl O_NONBLOCK", errno, err_r);
+ }
+ return 0;
+}
+
+int
+socket_accept(int listen_fd, auto_file& fd, const socket_args& args,
+ sockaddr_storage& addr_r, size_socket& addrlen_r, std::string& err_r)
+{
+ fd.reset(accept(listen_fd, reinterpret_cast<sockaddr *>(&addr_r),
+ &addrlen_r));
+ if (fd.get() < 0) {
+ return errno_string("accept", errno, err_r);
+ }
+ return socket_set_options(fd, args, err_r);
+}
+
+};
+
diff --git a/plugin/handler_socket/libhsclient/socket.hpp b/plugin/handler_socket/libhsclient/socket.hpp
new file mode 100644
index 00000000..c6e638c9
--- /dev/null
+++ b/plugin/handler_socket/libhsclient/socket.hpp
@@ -0,0 +1,51 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#ifndef DENA_SOCKET_HPP
+#define DENA_SOCKET_HPP
+
+#include <string>
+
+#include "auto_addrinfo.hpp"
+#include "auto_file.hpp"
+#include "config.hpp"
+
+namespace dena {
+
+struct socket_args {
+ sockaddr_storage addr;
+ size_socket addrlen;
+ int family;
+ int socktype;
+ int protocol;
+ int timeout;
+ int listen_backlog;
+ bool reuseaddr;
+ bool nonblocking;
+ bool use_epoll;
+ int sndbuf;
+ int rcvbuf;
+ socket_args() : addr(), addrlen(0), family(AF_INET), socktype(SOCK_STREAM),
+ protocol(0), timeout(600), listen_backlog(256),
+ reuseaddr(true), nonblocking(false), use_epoll(false),
+ sndbuf(0), rcvbuf(0) { }
+ void set(const config& conf);
+ void set_unix_domain(const char *path);
+ int resolve(const char *node, const char *service);
+};
+
+void ignore_sigpipe();
+int socket_bind(auto_file& fd, const socket_args& args, std::string& err_r);
+int socket_connect(auto_file& fd, const socket_args& args, std::string& err_r);
+int socket_accept(int listen_fd, auto_file& fd, const socket_args& args,
+ sockaddr_storage& addr_r, size_socket& addrlen_r, std::string& err_r);
+
+};
+
+#endif
+
diff --git a/plugin/handler_socket/libhsclient/string_buffer.hpp b/plugin/handler_socket/libhsclient/string_buffer.hpp
new file mode 100644
index 00000000..708c0df3
--- /dev/null
+++ b/plugin/handler_socket/libhsclient/string_buffer.hpp
@@ -0,0 +1,118 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#ifndef DENA_STRING_BUFFER_HPP
+#define DENA_STRING_BUFFER_HPP
+
+#include <vector>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.hpp"
+#include "allocator.hpp"
+#include "fatal.hpp"
+
+namespace dena {
+
+struct string_buffer : private noncopyable {
+ string_buffer() : buffer(0), begin_offset(0), end_offset(0), alloc_size(0) { }
+ ~string_buffer() {
+ DENA_FREE(buffer);
+ }
+ const char *begin() const {
+ return buffer + begin_offset;
+ }
+ const char *end() const {
+ return buffer + end_offset;
+ }
+ char *begin() {
+ return buffer + begin_offset;
+ }
+ char *end() {
+ return buffer + end_offset;
+ }
+ size_t size() const {
+ return end_offset - begin_offset;
+ }
+ void clear() {
+ begin_offset = end_offset = 0;
+ }
+ void resize(size_t len) {
+ if (size() < len) {
+ reserve(len);
+ memset(buffer + end_offset, 0, len - size());
+ }
+ end_offset = begin_offset + len;
+ }
+ void reserve(size_t len) {
+ if (alloc_size >= begin_offset + len) {
+ return;
+ }
+ size_t asz = alloc_size;
+ while (asz < begin_offset + len) {
+ if (asz == 0) {
+ asz = 16;
+ }
+ const size_t asz_n = asz << 1;
+ if (asz_n < asz) {
+ fatal_abort("string_buffer::resize() overflow");
+ }
+ asz = asz_n;
+ }
+ void *const p = DENA_REALLOC(buffer, asz);
+ if (p == 0) {
+ fatal_abort("string_buffer::resize() realloc");
+ }
+ buffer = static_cast<char *>(p);
+ alloc_size = asz;
+ }
+ void erase_front(size_t len) {
+ if (len >= size()) {
+ clear();
+ } else {
+ begin_offset += len;
+ }
+ }
+ char *make_space(size_t len) {
+ reserve(size() + len);
+ return buffer + end_offset;
+ }
+ void space_wrote(size_t len) {
+ len = std::min(len, alloc_size - end_offset);
+ end_offset += len;
+ }
+ template <size_t N>
+ void append_literal(const char (& str)[N]) {
+ append(str, str + N - 1);
+ }
+ void append(const char *start, const char *finish) {
+ const size_t len = finish - start;
+ reserve(size() + len);
+ memcpy(buffer + end_offset, start, len);
+ end_offset += len;
+ }
+ void append_2(const char *s1, const char *f1, const char *s2,
+ const char *f2) {
+ const size_t l1 = f1 - s1;
+ const size_t l2 = f2 - s2;
+ reserve(end_offset + l1 + l2);
+ memcpy(buffer + end_offset, s1, l1);
+ memcpy(buffer + end_offset + l1, s2, l2);
+ end_offset += l1 + l2;
+ }
+ private:
+ char *buffer;
+ size_t begin_offset;
+ size_t end_offset;
+ size_t alloc_size;
+};
+
+};
+
+#endif
+
diff --git a/plugin/handler_socket/libhsclient/string_ref.hpp b/plugin/handler_socket/libhsclient/string_ref.hpp
new file mode 100644
index 00000000..c5f93065
--- /dev/null
+++ b/plugin/handler_socket/libhsclient/string_ref.hpp
@@ -0,0 +1,63 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#ifndef DENA_STRING_REF_HPP
+#define DENA_STRING_REF_HPP
+
+#include <vector>
+#include <string.h>
+
+namespace dena {
+
+struct string_wref {
+ typedef char value_type;
+ char *begin() const { return start; }
+ char *end() const { return start + length; }
+ size_t size() const { return length; }
+ private:
+ char *start;
+ size_t length;
+ public:
+ string_wref(char *s = 0, size_t len = 0) : start(s), length(len) { }
+};
+
+struct string_ref {
+ typedef const char value_type;
+ const char *begin() const { return start; }
+ const char *end() const { return start + length; }
+ size_t size() const { return length; }
+ private:
+ const char *start;
+ size_t length;
+ public:
+ string_ref(const char *s = 0, size_t len = 0) : start(s), length(len) { }
+ string_ref(const char *s, const char *f) : start(s), length(f - s) { }
+ string_ref(const string_wref& w) : start(w.begin()), length(w.size()) { }
+};
+
+template <size_t N> inline bool
+operator ==(const string_ref& x, const char (& y)[N]) {
+ return (x.size() == N - 1) && (::memcmp(x.begin(), y, N - 1) == 0);
+}
+
+inline bool
+operator ==(const string_ref& x, const string_ref& y) {
+ return (x.size() == y.size()) &&
+ (::memcmp(x.begin(), y.begin(), x.size()) == 0);
+}
+
+inline bool
+operator !=(const string_ref& x, const string_ref& y) {
+ return (x.size() != y.size()) ||
+ (::memcmp(x.begin(), y.begin(), x.size()) != 0);
+}
+
+};
+
+#endif
+
diff --git a/plugin/handler_socket/libhsclient/string_util.cpp b/plugin/handler_socket/libhsclient/string_util.cpp
new file mode 100644
index 00000000..8ee6000f
--- /dev/null
+++ b/plugin/handler_socket/libhsclient/string_util.cpp
@@ -0,0 +1,182 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+
+#include "string_util.hpp"
+
+namespace dena {
+
+string_wref
+get_token(char *& wp, char *wp_end, char delim)
+{
+ char *const wp_begin = wp;
+ char *const p = memchr_char(wp_begin, delim, wp_end - wp_begin);
+ if (p == 0) {
+ wp = wp_end;
+ return string_wref(wp_begin, wp_end - wp_begin);
+ }
+ wp = p + 1;
+ return string_wref(wp_begin, p - wp_begin);
+}
+
+template <typename T> T
+atoi_tmpl_nocheck(const char *start, const char *finish)
+{
+ T v = 0;
+ for (; start != finish; ++start) {
+ const char c = *start;
+ if (c < '0' || c > '9') {
+ break;
+ }
+ v *= 10;
+ v += static_cast<T>(c - '0');
+ }
+ return v;
+}
+
+template <typename T> T
+atoi_signed_tmpl_nocheck(const char *start, const char *finish)
+{
+ T v = 0;
+ bool negative = false;
+ if (start != finish) {
+ if (start[0] == '-') {
+ ++start;
+ negative = true;
+ } else if (start[0] == '+') {
+ ++start;
+ }
+ }
+ for (; start != finish; ++start) {
+ const char c = *start;
+ if (c < '0' || c > '9') {
+ break;
+ }
+ v *= 10;
+ if (negative) {
+ v -= static_cast<T>(c - '0');
+ } else {
+ v += static_cast<T>(c - '0');
+ }
+ }
+ return v;
+}
+
+uint32_t
+atoi_uint32_nocheck(const char *start, const char *finish)
+{
+ return atoi_tmpl_nocheck<uint32_t>(start, finish);
+}
+
+long long
+atoll_nocheck(const char *start, const char *finish)
+{
+ return atoi_signed_tmpl_nocheck<long long>(start, finish);
+}
+
+void
+append_uint32(string_buffer& buf, uint32_t v)
+{
+ char *const wp = buf.make_space(64);
+ const int len = snprintf(wp, 64, "%lu", static_cast<unsigned long>(v));
+ if (len > 0) {
+ buf.space_wrote(len);
+ }
+}
+
+std::string
+to_stdstring(uint32_t v)
+{
+ char buf[64];
+ snprintf(buf, sizeof(buf), "%lu", static_cast<unsigned long>(v));
+ return std::string(buf);
+}
+
+int
+errno_string(const char *s, int en, std::string& err_r)
+{
+ char buf[64];
+ snprintf(buf, sizeof(buf), "%s: %d", s, en);
+ err_r = std::string(buf);
+ return en;
+}
+
+template <typename T> size_t
+split_tmpl_arr(char delim, const T& buf, T *parts, size_t parts_len)
+{
+ typedef typename T::value_type value_type;
+ size_t i = 0;
+ value_type *start = buf.begin();
+ value_type *const finish = buf.end();
+ for (i = 0; i < parts_len; ++i) {
+ value_type *const p = memchr_char(start, delim, finish - start);
+ if (p == 0) {
+ parts[i] = T(start, finish - start);
+ ++i;
+ break;
+ }
+ parts[i] = T(start, p - start);
+ start = p + 1;
+ }
+ const size_t r = i;
+ for (; i < parts_len; ++i) {
+ parts[i] = T();
+ }
+ return r;
+}
+
+size_t
+split(char delim, const string_ref& buf, string_ref *parts,
+ size_t parts_len)
+{
+ return split_tmpl_arr(delim, buf, parts, parts_len);
+}
+
+size_t
+split(char delim, const string_wref& buf, string_wref *parts,
+ size_t parts_len)
+{
+ return split_tmpl_arr(delim, buf, parts, parts_len);
+}
+
+template <typename T, typename V> size_t
+split_tmpl_vec(char delim, const T& buf, V& parts)
+{
+ typedef typename T::value_type value_type;
+ size_t i = 0;
+ value_type *start = buf.begin();
+ value_type *const finish = buf.end();
+ while (true) {
+ value_type *const p = memchr_char(start, delim, finish - start);
+ if (p == 0) {
+ parts.push_back(T(start, finish - start));
+ break;
+ }
+ parts.push_back(T(start, p - start));
+ start = p + 1;
+ }
+ const size_t r = i;
+ return r;
+}
+
+size_t
+split(char delim, const string_ref& buf, std::vector<string_ref>& parts_r)
+{
+ return split_tmpl_vec(delim, buf, parts_r);
+}
+
+size_t
+split(char delim, const string_wref& buf, std::vector<string_wref>& parts_r)
+{
+ return split_tmpl_vec(delim, buf, parts_r);
+}
+
+};
+
diff --git a/plugin/handler_socket/libhsclient/string_util.hpp b/plugin/handler_socket/libhsclient/string_util.hpp
new file mode 100644
index 00000000..45cc5b00
--- /dev/null
+++ b/plugin/handler_socket/libhsclient/string_util.hpp
@@ -0,0 +1,53 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#ifndef DENA_STRING_UTIL_HPP
+#define DENA_STRING_UTIL_HPP
+
+#include <string>
+#include <string.h>
+#include <stdint.h>
+
+#include "string_buffer.hpp"
+#include "string_ref.hpp"
+
+namespace dena {
+
+inline const char *
+memchr_char(const char *s, int c, size_t n)
+{
+ return static_cast<const char *>(memchr(s, c, n));
+}
+
+inline char *
+memchr_char(char *s, int c, size_t n)
+{
+ return static_cast<char *>(memchr(s, c, n));
+}
+
+string_wref get_token(char *& wp, char *wp_end, char delim);
+uint32_t atoi_uint32_nocheck(const char *start, const char *finish);
+std::string to_stdstring(uint32_t v);
+void append_uint32(string_buffer& buf, uint32_t v);
+long long atoll_nocheck(const char *start, const char *finish);
+
+int errno_string(const char *s, int en, std::string& err_r);
+
+size_t split(char delim, const string_ref& buf, string_ref *parts,
+ size_t parts_len);
+size_t split(char delim, const string_wref& buf, string_wref *parts,
+ size_t parts_len);
+size_t split(char delim, const string_ref& buf,
+ std::vector<string_ref>& parts_r);
+size_t split(char delim, const string_wref& buf,
+ std::vector<string_wref>& parts_r);
+
+};
+
+#endif
+
diff --git a/plugin/handler_socket/libhsclient/thread.hpp b/plugin/handler_socket/libhsclient/thread.hpp
new file mode 100644
index 00000000..8a436554
--- /dev/null
+++ b/plugin/handler_socket/libhsclient/thread.hpp
@@ -0,0 +1,84 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#ifndef DENA_THREAD_HPP
+#define DENA_THREAD_HPP
+
+#include <stdexcept>
+#include <pthread.h>
+
+#include "fatal.hpp"
+
+namespace dena {
+
+template <typename T>
+struct thread : private noncopyable {
+ template <typename Ta> thread(const Ta& arg, size_t stack_sz = 256 * 1024)
+ : obj(arg), thr(0), need_join(false), stack_size(stack_sz) { }
+ template <typename Ta0, typename Ta1> thread(const Ta0& a0,
+ volatile Ta1& a1, size_t stack_sz = 256 * 1024)
+ : obj(a0, a1), thr(0), need_join(false), stack_size(stack_sz) { }
+ ~thread() {
+ join();
+ }
+ void start() {
+ if (!start_nothrow()) {
+ fatal_abort("thread::start");
+ }
+ }
+ bool start_nothrow() {
+ if (need_join) {
+ return need_join; /* true */
+ }
+ void *const arg = this;
+ pthread_attr_t attr;
+ if (pthread_attr_init(&attr) != 0) {
+ fatal_abort("pthread_attr_init");
+ }
+ if (pthread_attr_setstacksize(&attr, stack_size) != 0) {
+ fatal_abort("pthread_attr_setstacksize");
+ }
+ const int r = pthread_create(&thr, &attr, thread_main, arg);
+ if (pthread_attr_destroy(&attr) != 0) {
+ fatal_abort("pthread_attr_destroy");
+ }
+ if (r != 0) {
+ return need_join; /* false */
+ }
+ need_join = true;
+ return need_join; /* true */
+ }
+ void join() {
+ if (!need_join) {
+ return;
+ }
+ int e = 0;
+ if ((e = pthread_join(thr, 0)) != 0) {
+ fatal_abort("pthread_join");
+ }
+ need_join = false;
+ }
+ T& operator *() { return obj; }
+ T *operator ->() { return &obj; }
+ private:
+ static void *thread_main(void *arg) {
+ thread *p = static_cast<thread *>(arg);
+ p->obj();
+ return 0;
+ }
+ private:
+ T obj;
+ pthread_t thr;
+ bool need_join;
+ size_t stack_size;
+};
+
+};
+
+#endif
+
diff --git a/plugin/handler_socket/libhsclient/util.hpp b/plugin/handler_socket/libhsclient/util.hpp
new file mode 100644
index 00000000..93d78cc7
--- /dev/null
+++ b/plugin/handler_socket/libhsclient/util.hpp
@@ -0,0 +1,25 @@
+
+// vim:sw=2:ai
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#ifndef DENA_UTIL_HPP
+#define DENA_UTIL_HPP
+
+namespace dena {
+
+/* boost::noncopyable */
+struct noncopyable {
+ noncopyable() { }
+ private:
+ noncopyable(const noncopyable&);
+ noncopyable& operator =(const noncopyable&);
+};
+
+};
+
+#endif
+
diff --git a/plugin/handler_socket/misc/microbench-hs.log b/plugin/handler_socket/misc/microbench-hs.log
new file mode 100644
index 00000000..9fffe12e
--- /dev/null
+++ b/plugin/handler_socket/misc/microbench-hs.log
@@ -0,0 +1,130 @@
+[a@c54hdd libhsclient]$ ./hstest_hs.sh host=192.168.100.104 key_mask=1000000 num_threads=100 num=10000000 timelimit=10 dbname=hstest
+now: 1274127653 cntdiff: 265538 tdiff: 1.000996 rps: 265273.757409
+now: 1274127654 cntdiff: 265762 tdiff: 1.000995 rps: 265497.850684
+now: 1274127655 cntdiff: 265435 tdiff: 1.001010 rps: 265167.196749
+now: 1274127656 cntdiff: 265144 tdiff: 1.000994 rps: 264880.654203
+now: 1274127657 cntdiff: 265593 tdiff: 1.000995 rps: 265329.018659
+now: 1274127658 cntdiff: 264863 tdiff: 1.000996 rps: 264599.492138
+now: 1274127659 cntdiff: 265688 tdiff: 1.001008 rps: 265420.447231
+now: 1274127660 cntdiff: 265727 tdiff: 1.000999 rps: 265461.810594
+now: 1274127661 cntdiff: 265848 tdiff: 1.001010 rps: 265579.716809
+now: 1274127662 cntdiff: 265430 tdiff: 1.000992 rps: 265167.001723
+now: 1274127663 cntdiff: 266379 tdiff: 1.001008 rps: 266110.751381
+now: 1274127664 cntdiff: 266244 tdiff: 1.001003 rps: 265977.217679
+now: 1274127665 cntdiff: 265737 tdiff: 1.000996 rps: 265472.559379
+now: 1274127666 cntdiff: 265878 tdiff: 1.001003 rps: 265611.647683
+(1274127656.104648: 1328292, 1274127666.114649: 3985679), 265473.20173 qps
+
+
+*************************** 1. row ***************************
+ Type: InnoDB
+ Name:
+Status:
+=====================================
+100518 5:18:13 INNODB MONITOR OUTPUT
+=====================================
+Per second averages calculated from the last 5 seconds
+----------
+BACKGROUND THREAD
+----------
+srv_master_thread loops: 191 1_second, 190 sleeps, 18 10_second, 5 background, 5 flush
+srv_master_thread log flush and writes: 190
+----------
+SEMAPHORES
+----------
+OS WAIT ARRAY INFO: reservation count 53519, signal count 29547
+Mutex spin waits 3083488, rounds 5159906, OS waits 50700
+RW-shared spins 21, OS waits 16; RW-excl spins 1, OS waits 4
+Spin rounds per wait: 1.67 mutex, 30.00 RW-shared, 151.00 RW-excl
+------------
+TRANSACTIONS
+------------
+Trx id counter EDA36085
+Purge done for trx's n:o < EC1F94A7 undo n:o < 0
+History list length 20
+LIST OF TRANSACTIONS FOR EACH SESSION:
+---TRANSACTION 0, not started, process no 4533, OS thread id 1079281984
+MySQL thread id 11, query id 16 localhost root
+show engine innodb status
+---TRANSACTION ED9D5959, not started, process no 4533, OS thread id 1089849664
+MySQL thread id 7, query id 0 handlersocket: mode=rd, 0 conns, 0 active
+---TRANSACTION ED9D5956, not started, process no 4533, OS thread id 1238796608
+MySQL thread id 1, query id 0 handlersocket: mode=rd, 0 conns, 0 active
+---TRANSACTION EDA36084, not started, process no 4533, OS thread id 1255582016
+mysql tables in use 1, locked 1
+MySQL thread id 3, query id 0 handlersocket: mode=rd, 12 conns, 7 active
+---TRANSACTION EDA36080, not started, process no 4533, OS thread id 1247189312
+mysql tables in use 1, locked 1
+MySQL thread id 2, query id 0 handlersocket: mode=rd, 36 conns, 18 active
+---TRANSACTION EDA36082, ACTIVE 0 sec, process no 4533, OS thread id 1263974720 committing
+MySQL thread id 4, query id 0 handlersocket: mode=rd, 37 conns, 20 active
+Trx read view will not see trx with id >= EDA36083, sees < EDA3607D
+---TRANSACTION EDA3607D, ACTIVE 0 sec, process no 4533, OS thread id 1272367424, thread declared inside InnoDB 500
+mysql tables in use 1, locked 1
+MySQL thread id 5, query id 0 handlersocket: mode=rd, 15 conns, 9 active
+Trx read view will not see trx with id >= EDA3607E, sees < EDA36079
+--------
+FILE I/O
+--------
+I/O thread 0 state: waiting for i/o request (insert buffer thread)
+I/O thread 1 state: waiting for i/o request (log thread)
+I/O thread 2 state: waiting for i/o request (read thread)
+I/O thread 3 state: waiting for i/o request (read thread)
+I/O thread 4 state: waiting for i/o request (read thread)
+I/O thread 5 state: waiting for i/o request (read thread)
+I/O thread 6 state: waiting for i/o request (write thread)
+I/O thread 7 state: waiting for i/o request (write thread)
+I/O thread 8 state: waiting for i/o request (write thread)
+I/O thread 9 state: waiting for i/o request (write thread)
+Pending normal aio reads: 0, aio writes: 0,
+ ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0
+Pending flushes (fsync) log: 0; buffer pool: 0
+71 OS file reads, 235 OS file writes, 235 OS fsyncs
+0.00 reads/s, 0 avg bytes/read, 1.00 writes/s, 1.00 fsyncs/s
+-------------------------------------
+INSERT BUFFER AND ADAPTIVE HASH INDEX
+-------------------------------------
+Ibuf: size 1, free list len 0, seg size 2,
+0 inserts, 0 merged recs, 0 merges
+Hash table size 12750011, node heap has 2 buffer(s)
+267203.76 hash searches/s, 0.00 non-hash searches/s
+---
+LOG
+---
+Log sequence number 147179727377
+Log flushed up to 147179726685
+Last checkpoint at 147179716475
+0 pending log writes, 0 pending chkp writes
+194 log i/o's done, 1.00 log i/o's/second
+----------------------
+BUFFER POOL AND MEMORY
+----------------------
+Total memory allocated 6587154432; in additional pool allocated 0
+Dictionary memory allocated 33640
+Buffer pool size 393216
+Free buffers 393154
+Database pages 60
+Old database pages 0
+Modified db pages 1
+Pending reads 0
+Pending writes: LRU 0, flush list 0, single page 0
+Pages made young 0, not young 0
+0.00 youngs/s, 0.00 non-youngs/s
+Pages read 60, created 0, written 23
+0.00 reads/s, 0.00 creates/s, 0.00 writes/s
+Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not 0 / 1000
+Pages read ahead 0.00/s, evicted without access 0.00/s
+LRU len: 60, unzip_LRU len: 0
+I/O sum[0]:cur[0], unzip sum[0]:cur[0]
+--------------
+ROW OPERATIONS
+--------------
+2 queries inside InnoDB, 0 queries in queue
+3 read views open inside InnoDB
+Main thread process no. 4533, id 1230403904, state: sleeping
+Number of rows inserted 0, updated 0, deleted 0, read 37653556
+0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 266608.28 reads/s
+----------------------------
+END OF INNODB MONITOR OUTPUT
+============================
+
diff --git a/plugin/handler_socket/misc/microbench-my.log b/plugin/handler_socket/misc/microbench-my.log
new file mode 100644
index 00000000..2477af8a
--- /dev/null
+++ b/plugin/handler_socket/misc/microbench-my.log
@@ -0,0 +1,125 @@
+
+[a@c54hdd libhsclient]$ ./hstest_my.sh host=192.168.100.104 key_mask=1000000 num_threads=100 num=10000000 timelimit=10 dbname=hstest
+now: 1274128046 cntdiff: 63061 tdiff: 1.000999 rps: 62998.066579
+now: 1274128047 cntdiff: 61227 tdiff: 1.001013 rps: 61165.037337
+now: 1274128048 cntdiff: 61367 tdiff: 1.001029 rps: 61303.917375
+now: 1274128049 cntdiff: 61959 tdiff: 1.000962 rps: 61899.451554
+now: 1274128050 cntdiff: 62176 tdiff: 1.001006 rps: 62113.520756
+now: 1274128051 cntdiff: 61367 tdiff: 1.000998 rps: 61305.815559
+now: 1274128052 cntdiff: 61644 tdiff: 1.001015 rps: 61581.497988
+now: 1274128053 cntdiff: 60659 tdiff: 1.000984 rps: 60599.373036
+now: 1274128054 cntdiff: 59459 tdiff: 1.000996 rps: 59399.831067
+now: 1274128055 cntdiff: 62310 tdiff: 1.001011 rps: 62247.074757
+now: 1274128056 cntdiff: 61947 tdiff: 1.000991 rps: 61885.664744
+now: 1274128057 cntdiff: 60675 tdiff: 1.001006 rps: 60614.029076
+now: 1274128058 cntdiff: 60312 tdiff: 1.001001 rps: 60251.680861
+now: 1274128059 cntdiff: 60290 tdiff: 1.001004 rps: 60229.530717
+(1274128049.309634: 309654, 1274128059.319648: 920493), 61022.79143 qps
+
+*************************** 1. row ***************************
+ Type: InnoDB
+ Name:
+Status:
+=====================================
+100518 5:24:51 INNODB MONITOR OUTPUT
+=====================================
+Per second averages calculated from the last 5 seconds
+----------
+BACKGROUND THREAD
+----------
+srv_master_thread loops: 220 1_second, 219 sleeps, 21 10_second, 6 background, 6 flush
+srv_master_thread log flush and writes: 219
+----------
+SEMAPHORES
+----------
+OS WAIT ARRAY INFO: reservation count 56193, signal count 30826
+Mutex spin waits 3415153, rounds 5618661, OS waits 53251
+RW-shared spins 24, OS waits 17; RW-excl spins 1, OS waits 5
+Spin rounds per wait: 1.65 mutex, 30.00 RW-shared, 181.00 RW-excl
+------------
+TRANSACTIONS
+------------
+Trx id counter EDB514D6
+Purge done for trx's n:o < EC1F94A7 undo n:o < 0
+History list length 20
+LIST OF TRANSACTIONS FOR EACH SESSION:
+---TRANSACTION 0, not started, process no 4533, OS thread id 1306585408
+MySQL thread id 113, query id 920620 localhost root
+show engine innodb status
+---TRANSACTION EDA708BB, not started, process no 4533, OS thread id 1272367424
+MySQL thread id 5, query id 0 handlersocket: mode=rd, 0 conns, 0 active
+---TRANSACTION ED9D5959, not started, process no 4533, OS thread id 1089849664
+MySQL thread id 7, query id 0 handlersocket: mode=rd, 0 conns, 0 active
+---TRANSACTION ED9D5956, not started, process no 4533, OS thread id 1238796608
+MySQL thread id 1, query id 0 handlersocket: mode=rd, 0 conns, 0 active
+---TRANSACTION EDA708BD, not started, process no 4533, OS thread id 1255582016
+MySQL thread id 3, query id 0 handlersocket: mode=rd, 0 conns, 0 active
+---TRANSACTION EDA708BF, not started, process no 4533, OS thread id 1247189312
+MySQL thread id 2, query id 0 handlersocket: mode=rd, 0 conns, 0 active
+---TRANSACTION EDA708BE, not started, process no 4533, OS thread id 1263974720
+MySQL thread id 4, query id 0 handlersocket: mode=rd, 0 conns, 0 active
+--------
+FILE I/O
+--------
+I/O thread 0 state: waiting for i/o request (insert buffer thread)
+I/O thread 1 state: waiting for i/o request (log thread)
+I/O thread 2 state: waiting for i/o request (read thread)
+I/O thread 3 state: waiting for i/o request (read thread)
+I/O thread 4 state: waiting for i/o request (read thread)
+I/O thread 5 state: waiting for i/o request (read thread)
+I/O thread 6 state: waiting for i/o request (write thread)
+I/O thread 7 state: waiting for i/o request (write thread)
+I/O thread 8 state: waiting for i/o request (write thread)
+I/O thread 9 state: waiting for i/o request (write thread)
+Pending normal aio reads: 0, aio writes: 0,
+ ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0
+Pending flushes (fsync) log: 0; buffer pool: 0
+71 OS file reads, 269 OS file writes, 269 OS fsyncs
+0.00 reads/s, 0 avg bytes/read, 2.40 writes/s, 2.40 fsyncs/s
+-------------------------------------
+INSERT BUFFER AND ADAPTIVE HASH INDEX
+-------------------------------------
+Ibuf: size 1, free list len 0, seg size 2,
+0 inserts, 0 merged recs, 0 merges
+Hash table size 12750011, node heap has 2 buffer(s)
+65739.45 hash searches/s, 0.00 non-hash searches/s
+---
+LOG
+---
+Log sequence number 147179774153
+Log flushed up to 147179771813
+Last checkpoint at 147179761899
+0 pending log writes, 0 pending chkp writes
+220 log i/o's done, 1.60 log i/o's/second
+----------------------
+BUFFER POOL AND MEMORY
+----------------------
+Total memory allocated 6587154432; in additional pool allocated 0
+Dictionary memory allocated 33640
+Buffer pool size 393216
+Free buffers 393154
+Database pages 60
+Old database pages 0
+Modified db pages 1
+Pending reads 0
+Pending writes: LRU 0, flush list 0, single page 0
+Pages made young 0, not young 0
+0.00 youngs/s, 0.00 non-youngs/s
+Pages read 60, created 0, written 27
+0.00 reads/s, 0.00 creates/s, 0.40 writes/s
+Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not 0 / 1000
+Pages read ahead 0.00/s, evicted without access 0.00/s
+LRU len: 60, unzip_LRU len: 0
+I/O sum[0]:cur[0], unzip sum[0]:cur[0]
+--------------
+ROW OPERATIONS
+--------------
+0 queries inside InnoDB, 0 queries in queue
+1 read views open inside InnoDB
+Main thread process no. 4533, id 1230403904, state: sleeping
+Number of rows inserted 0, updated 0, deleted 0, read 40071920
+0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 66321.54 reads/s
+----------------------------
+END OF INNODB MONITOR OUTPUT
+============================
+
diff --git a/plugin/handler_socket/perl-Net-HandlerSocket/COPYRIGHT.txt b/plugin/handler_socket/perl-Net-HandlerSocket/COPYRIGHT.txt
new file mode 100644
index 00000000..41dda127
--- /dev/null
+++ b/plugin/handler_socket/perl-Net-HandlerSocket/COPYRIGHT.txt
@@ -0,0 +1,27 @@
+
+ Copyright (c) 2010 DeNA Co.,Ltd.
+ 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 DeNA Co.,Ltd. nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY DeNA Co.,Ltd. "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 DeNA Co.,Ltd. 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.
+
diff --git a/plugin/handler_socket/perl-Net-HandlerSocket/Changes b/plugin/handler_socket/perl-Net-HandlerSocket/Changes
new file mode 100644
index 00000000..7ed1e019
--- /dev/null
+++ b/plugin/handler_socket/perl-Net-HandlerSocket/Changes
@@ -0,0 +1,6 @@
+Revision history for Perl extension HandlerSocket.
+
+0.01 Wed Mar 31 11:50:23 2010
+ - original version; created by h2xs 1.23 with options
+ -A -n HandlerSocket
+
diff --git a/plugin/handler_socket/perl-Net-HandlerSocket/HandlerSocket.xs b/plugin/handler_socket/perl-Net-HandlerSocket/HandlerSocket.xs
new file mode 100644
index 00000000..8169b3e5
--- /dev/null
+++ b/plugin/handler_socket/perl-Net-HandlerSocket/HandlerSocket.xs
@@ -0,0 +1,634 @@
+
+// vim:ai:sw=2:ts=8
+
+/*
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ * See COPYRIGHT.txt for details.
+ */
+
+#undef VERSION
+#include <config.h>
+
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+
+#include "ppport.h"
+#include "hstcpcli.hpp"
+
+#define DBG(x)
+
+static SV *
+arr_get_entry(AV *av, I32 avmax, I32 idx)
+{
+ if (idx > avmax) {
+ DBG(fprintf(stderr, "arr_get_entry1 %d %d\n", avmax, idx));
+ return 0;
+ }
+ SV **const ev = av_fetch(av, idx, 0);
+ if (ev == 0) {
+ DBG(fprintf(stderr, "arr_get_entry2 %d %d\n", avmax, idx));
+ return 0;
+ }
+ return *ev;
+}
+
+static int
+arr_get_intval(AV *av, I32 avmax, I32 idx, int default_val = 0)
+{
+ SV *const e = arr_get_entry(av, avmax, idx);
+ if (e == 0) {
+ return default_val;
+ }
+ return SvIV(e);
+}
+
+static const char *
+sv_get_strval(SV *sv)
+{
+ if (sv == 0 || !SvPOK(sv)) {
+ DBG(fprintf(stderr, "sv_get_strval\n"));
+ return 0;
+ }
+ return SvPV_nolen(sv);
+}
+
+static const char *
+arr_get_strval(AV *av, I32 avmax, I32 idx)
+{
+ SV *const e = arr_get_entry(av, avmax, idx);
+ return sv_get_strval(e);
+}
+
+static AV *
+sv_get_arrval(SV *sv)
+{
+ if (sv == 0 || !SvROK(sv)) {
+ DBG(fprintf(stderr, "sv_get_arrval1\n"));
+ return 0;
+ }
+ SV *const svtarget = SvRV(sv);
+ if (svtarget == 0 || SvTYPE(svtarget) != SVt_PVAV) {
+ DBG(fprintf(stderr, "sv_get_arrval2\n"));
+ return 0;
+ }
+ return (AV *)svtarget;
+}
+
+static AV *
+arr_get_arrval(AV *av, I32 avmax, I32 idx)
+{
+ SV *const e = arr_get_entry(av, avmax, idx);
+ if (e == 0) {
+ DBG(fprintf(stderr, "arr_get_arrval1\n"));
+ return 0;
+ }
+ return sv_get_arrval(e);
+}
+
+static void
+hv_to_strmap(HV *hv, std::map<std::string, std::string>& m_r)
+{
+ if (hv == 0) {
+ return;
+ }
+ hv_iterinit(hv);
+ HE *hent = 0;
+ while ((hent = hv_iternext(hv)) != 0) {
+ I32 klen = 0;
+ char *const k = hv_iterkey(hent, &klen);
+ DBG(fprintf(stderr, "k=%s\n", k));
+ const std::string key(k, klen);
+ SV *const vsv = hv_iterval(hv, hent);
+ STRLEN vlen = 0;
+ char *const v = SvPV(vsv, vlen);
+ DBG(fprintf(stderr, "v=%s\n", v));
+ const std::string val(v, vlen);
+ m_r[key] = val;
+ }
+}
+
+static void
+strrefarr_push_back(std::vector<dena::string_ref>& a_r, SV *sv)
+{
+ if (sv == 0 || SvTYPE(sv) == SVt_NULL) { /* !SvPOK()? */
+ DBG(fprintf(stderr, "strrefarr_push_back: null\n"));
+ return a_r.push_back(dena::string_ref());
+ }
+ STRLEN vlen = 0;
+ char *const v = SvPV(sv, vlen);
+ DBG(fprintf(stderr, "strrefarr_push_back: %s\n", v));
+ a_r.push_back(dena::string_ref(v, vlen));
+}
+
+static void
+av_to_strrefarr(AV *av, std::vector<dena::string_ref>& a_r)
+{
+ if (av == 0) {
+ return;
+ }
+ const I32 len = av_len(av) + 1;
+ for (I32 i = 0; i < len; ++i) {
+ SV **const ev = av_fetch(av, i, 0);
+ strrefarr_push_back(a_r, ev ? *ev : 0);
+ }
+}
+
+static dena::string_ref
+sv_get_string_ref(SV *sv)
+{
+ if (sv == 0 || SvTYPE(sv) == SVt_NULL) { /* !SvPOK()? */
+ return dena::string_ref();
+ }
+ STRLEN vlen = 0;
+ char *const v = SvPV(sv, vlen);
+ return dena::string_ref(v, vlen);
+}
+
+static IV
+sv_get_iv(SV *sv)
+{
+ if (sv == 0 || ( !SvIOK(sv) && !SvPOK(sv) ) ) {
+ return 0;
+ }
+ return SvIV(sv);
+}
+
+static void
+av_to_filters(AV *av, std::vector<dena::hstcpcli_filter>& f_r)
+{
+ DBG(fprintf(stderr, "av_to_filters: %p\n", av));
+ if (av == 0) {
+ return;
+ }
+ const I32 len = av_len(av) + 1;
+ DBG(fprintf(stderr, "av_to_filters: len=%d\n", (int)len));
+ for (I32 i = 0; i < len; ++i) {
+ AV *const earr = arr_get_arrval(av, len, i);
+ if (earr == 0) {
+ continue;
+ }
+ const I32 earrlen = av_len(earr) + 1;
+ dena::hstcpcli_filter fe;
+ fe.filter_type = sv_get_string_ref(arr_get_entry(earr, earrlen, 0));
+ fe.op = sv_get_string_ref(arr_get_entry(earr, earrlen, 1));
+ fe.ff_offset = sv_get_iv(arr_get_entry(earr, earrlen, 2));
+ fe.val = sv_get_string_ref(arr_get_entry(earr, earrlen, 3));
+ f_r.push_back(fe);
+ DBG(fprintf(stderr, "av_to_filters: %s %s %d %s\n",
+ fe.filter_action.begin(), fe.filter_op.begin(), (int)fe.ff_offset,
+ fe.value.begin()));
+ }
+}
+
+static void
+set_process_verbose_level(const std::map<std::string, std::string>& m)
+{
+ std::map<std::string, std::string>::const_iterator iter = m.find("verbose");
+ if (iter != m.end()) {
+ dena::verbose_level = atoi(iter->second.c_str());
+ }
+}
+
+static AV *
+execute_internal(SV *obj, int id, const char *op, AV *keys, int limit,
+ int skip, const char *modop, AV *modvals, AV *filters, int invalues_keypart,
+ AV *invalues)
+{
+ AV *retval = (AV *)&PL_sv_undef;
+ dena::hstcpcli_i *const ptr =
+ reinterpret_cast<dena::hstcpcli_i *>(SvIV(SvRV(obj)));
+ do {
+ std::vector<dena::string_ref> keyarr, mvarr;
+ std::vector<dena::hstcpcli_filter> farr;
+ std::vector<dena::string_ref> ivs;
+ av_to_strrefarr(keys, keyarr);
+ dena::string_ref modop_ref;
+ if (modop != 0) {
+ modop_ref = dena::string_ref(modop, strlen(modop));
+ av_to_strrefarr(modvals, mvarr);
+ }
+ if (filters != 0) {
+ av_to_filters(filters, farr);
+ }
+ if (invalues_keypart >= 0 && invalues != 0) {
+ av_to_strrefarr(invalues, ivs);
+ }
+ ptr->request_buf_exec_generic(id, dena::string_ref(op, strlen(op)),
+ &keyarr[0], keyarr.size(), limit, skip, modop_ref, &mvarr[0],
+ mvarr.size(), &farr[0], farr.size(), invalues_keypart, &ivs[0],
+ ivs.size());
+ AV *const av = newAV();
+ retval = av;
+ if (ptr->request_send() != 0) {
+ break;
+ }
+ size_t nflds = 0;
+ ptr->response_recv(nflds);
+ const int e = ptr->get_error_code();
+ DBG(fprintf(stderr, "e=%d nflds=%zu\n", e, nflds));
+ av_push(av, newSViv(e));
+ if (e != 0) {
+ const std::string s = ptr->get_error();
+ av_push(av, newSVpvn(s.data(), s.size()));
+ } else {
+ const dena::string_ref *row = 0;
+ while ((row = ptr->get_next_row()) != 0) {
+ DBG(fprintf(stderr, "row=%p\n", row));
+ for (size_t i = 0; i < nflds; ++i) {
+ const dena::string_ref& v = row[i];
+ DBG(fprintf(stderr, "FLD %zu v=%s vbegin=%p\n", i,
+ std::string(v.begin(), v.size())
+ .c_str(), v.begin()));
+ if (v.begin() != 0) {
+ SV *const e = newSVpvn(
+ v.begin(), v.size());
+ av_push(av, e);
+ } else {
+ av_push(av, &PL_sv_undef);
+ }
+ }
+ }
+ }
+ if (e >= 0) {
+ ptr->response_buf_remove();
+ }
+ } while (0);
+ return retval;
+}
+
+struct execute_arg {
+ int id;
+ const char *op;
+ AV *keys;
+ int limit;
+ int skip;
+ const char *modop;
+ AV *modvals;
+ AV *filters;
+ int invalues_keypart;
+ AV *invalues;
+ execute_arg() : id(0), op(0), keys(0), limit(0), skip(0), modop(0),
+ modvals(0), filters(0), invalues_keypart(-1), invalues(0) { }
+};
+
+static AV *
+execute_multi_internal(SV *obj, const execute_arg *args, size_t num_args)
+{
+ dena::hstcpcli_i *const ptr =
+ reinterpret_cast<dena::hstcpcli_i *>(SvIV(SvRV(obj)));
+ /* appends multiple requests to the send buffer */
+ for (size_t i = 0; i < num_args; ++i) {
+ std::vector<dena::string_ref> keyarr, mvarr;
+ std::vector<dena::hstcpcli_filter> farr;
+ std::vector<dena::string_ref> ivs;
+ const execute_arg& arg = args[i];
+ av_to_strrefarr(arg.keys, keyarr);
+ dena::string_ref modop_ref;
+ if (arg.modop != 0) {
+ modop_ref = dena::string_ref(arg.modop, strlen(arg.modop));
+ av_to_strrefarr(arg.modvals, mvarr);
+ }
+ if (arg.filters != 0) {
+ av_to_filters(arg.filters, farr);
+ }
+ if (arg.invalues_keypart >= 0 && arg.invalues != 0) {
+ av_to_strrefarr(arg.invalues, ivs);
+ }
+ ptr->request_buf_exec_generic(arg.id,
+ dena::string_ref(arg.op, strlen(arg.op)), &keyarr[0], keyarr.size(),
+ arg.limit, arg.skip, modop_ref, &mvarr[0], mvarr.size(), &farr[0],
+ farr.size(), arg.invalues_keypart, &ivs[0], ivs.size());
+ }
+ AV *const retval = newAV();
+ /* sends the requests */
+ if (ptr->request_send() < 0) {
+ /* IO error */
+ AV *const av_respent = newAV();
+ av_push(retval, newRV_noinc((SV *)av_respent));
+ av_push(av_respent, newSViv(ptr->get_error_code()));
+ const std::string& s = ptr->get_error();
+ av_push(av_respent, newSVpvn(s.data(), s.size()));
+ return retval; /* retval : [ [ err_code, err_message ] ] */
+ }
+ /* receives responses */
+ for (size_t i = 0; i < num_args; ++i) {
+ AV *const av_respent = newAV();
+ av_push(retval, newRV_noinc((SV *)av_respent));
+ size_t nflds = 0;
+ const int e = ptr->response_recv(nflds);
+ av_push(av_respent, newSViv(e));
+ if (e != 0) {
+ const std::string& s = ptr->get_error();
+ av_push(av_respent, newSVpvn(s.data(), s.size()));
+ } else {
+ const dena::string_ref *row = 0;
+ while ((row = ptr->get_next_row()) != 0) {
+ for (size_t i = 0; i < nflds; ++i) {
+ const dena::string_ref& v = row[i];
+ DBG(fprintf(stderr, "%zu %s\n", i,
+ std::string(v.begin(), v.size()).c_str()));
+ if (v.begin() != 0) {
+ av_push(av_respent, newSVpvn(v.begin(), v.size()));
+ } else {
+ /* null */
+ av_push(av_respent, &PL_sv_undef);
+ }
+ }
+ }
+ }
+ if (e >= 0) {
+ ptr->response_buf_remove();
+ }
+ if (e < 0) {
+ return retval;
+ }
+ }
+ return retval;
+}
+
+MODULE = Net::HandlerSocket PACKAGE = Net::HandlerSocket
+
+SV *
+new(klass, args)
+ char *klass
+ HV *args
+CODE:
+ RETVAL = &PL_sv_undef;
+ dena::config conf;
+ hv_to_strmap(args, conf);
+ set_process_verbose_level(conf);
+ dena::socket_args sargs;
+ sargs.set(conf);
+ dena::hstcpcli_ptr p = dena::hstcpcli_i::create(sargs);
+ SV *const objref = newSViv(0);
+ SV *const obj = newSVrv(objref, klass);
+ dena::hstcpcli_i *const ptr = p.get();
+ sv_setiv(obj, reinterpret_cast<IV>(ptr));
+ p.release();
+ SvREADONLY_on(obj);
+ RETVAL = objref;
+OUTPUT:
+ RETVAL
+
+void
+DESTROY(obj)
+ SV *obj
+CODE:
+ dena::hstcpcli_i *const ptr =
+ reinterpret_cast<dena::hstcpcli_i *>(SvIV(SvRV(obj)));
+ delete ptr;
+
+void
+close(obj)
+ SV *obj
+CODE:
+ dena::hstcpcli_i *const ptr =
+ reinterpret_cast<dena::hstcpcli_i *>(SvIV(SvRV(obj)));
+ ptr->close();
+
+int
+reconnect(obj)
+ SV *obj
+CODE:
+ RETVAL = 0;
+ dena::hstcpcli_i *const ptr =
+ reinterpret_cast<dena::hstcpcli_i *>(SvIV(SvRV(obj)));
+ RETVAL = ptr->reconnect();
+OUTPUT:
+ RETVAL
+
+int
+stable_point(obj)
+ SV *obj
+CODE:
+ RETVAL = 0;
+ dena::hstcpcli_i *const ptr =
+ reinterpret_cast<dena::hstcpcli_i *>(SvIV(SvRV(obj)));
+ const bool rv = ptr->stable_point();
+ RETVAL = static_cast<int>(rv);
+OUTPUT:
+ RETVAL
+
+int
+get_error_code(obj)
+ SV *obj
+CODE:
+ RETVAL = 0;
+ dena::hstcpcli_i *const ptr =
+ reinterpret_cast<dena::hstcpcli_i *>(SvIV(SvRV(obj)));
+ RETVAL = ptr->get_error_code();
+OUTPUT:
+ RETVAL
+
+SV *
+get_error(obj)
+ SV *obj
+CODE:
+ RETVAL = &PL_sv_undef;
+ dena::hstcpcli_i *const ptr =
+ reinterpret_cast<dena::hstcpcli_i *>(SvIV(SvRV(obj)));
+ const std::string s = ptr->get_error();
+ RETVAL = newSVpvn(s.data(), s.size());
+OUTPUT:
+ RETVAL
+
+int
+auth(obj, key, typ = 0)
+ SV *obj
+ const char *key
+ const char *typ
+CODE:
+ RETVAL = 0;
+ dena::hstcpcli_i *const ptr =
+ reinterpret_cast<dena::hstcpcli_i *>(SvIV(SvRV(obj)));
+ do {
+ ptr->request_buf_auth(key, typ);
+ if (ptr->request_send() != 0) {
+ break;
+ }
+ size_t nflds = 0;
+ ptr->response_recv(nflds);
+ const int e = ptr->get_error_code();
+ DBG(fprintf(stderr, "errcode=%d\n", ptr->get_error_code()));
+ if (e >= 0) {
+ ptr->response_buf_remove();
+ }
+ DBG(fprintf(stderr, "errcode=%d\n", ptr->get_error_code()));
+ } while (0);
+ RETVAL = ptr->get_error_code();
+OUTPUT:
+ RETVAL
+
+
+int
+open_index(obj, id, db, table, index, fields, ffields = 0)
+ SV *obj
+ int id
+ const char *db
+ const char *table
+ const char *index
+ const char *fields
+ SV *ffields
+CODE:
+ const char *const ffields_str = sv_get_strval(ffields);
+ RETVAL = 0;
+ dena::hstcpcli_i *const ptr =
+ reinterpret_cast<dena::hstcpcli_i *>(SvIV(SvRV(obj)));
+ do {
+ ptr->request_buf_open_index(id, db, table, index, fields, ffields_str);
+ if (ptr->request_send() != 0) {
+ break;
+ }
+ size_t nflds = 0;
+ ptr->response_recv(nflds);
+ const int e = ptr->get_error_code();
+ DBG(fprintf(stderr, "errcode=%d\n", ptr->get_error_code()));
+ if (e >= 0) {
+ ptr->response_buf_remove();
+ }
+ DBG(fprintf(stderr, "errcode=%d\n", ptr->get_error_code()));
+ } while (0);
+ RETVAL = ptr->get_error_code();
+OUTPUT:
+ RETVAL
+
+AV *
+execute_single(obj, id, op, keys, limit, skip, mop = 0, mvs = 0, fils = 0, ivkeypart = -1, ivs = 0)
+ SV *obj
+ int id
+ const char *op
+ AV *keys
+ int limit
+ int skip
+ SV *mop
+ SV *mvs
+ SV *fils
+ int ivkeypart
+ SV *ivs
+CODE:
+ const char *const mop_str = sv_get_strval(mop);
+ AV *const mvs_av = sv_get_arrval(mvs);
+ AV *const fils_av = sv_get_arrval(fils);
+ AV *const ivs_av = sv_get_arrval(ivs);
+ RETVAL = execute_internal(obj, id, op, keys, limit, skip, mop_str, mvs_av,
+ fils_av, ivkeypart, ivs_av);
+ sv_2mortal((SV *)RETVAL);
+OUTPUT:
+ RETVAL
+
+AV *
+execute_multi(obj, cmds)
+ SV *obj
+ AV *cmds
+CODE:
+ DBG(fprintf(stderr, "execute_multi0\n"));
+ const I32 cmdsmax = av_len(cmds);
+ execute_arg args[cmdsmax + 1]; /* GNU */
+ for (I32 i = 0; i <= cmdsmax; ++i) {
+ AV *const avtarget = arr_get_arrval(cmds, cmdsmax, i);
+ if (avtarget == 0) {
+ DBG(fprintf(stderr, "execute_multi1 %d\n", i));
+ continue;
+ }
+ const I32 argmax = av_len(avtarget);
+ if (argmax < 2) {
+ DBG(fprintf(stderr, "execute_multi2 %d\n", i));
+ continue;
+ }
+ execute_arg& ag = args[i];
+ ag.id = arr_get_intval(avtarget, argmax, 0);
+ ag.op = arr_get_strval(avtarget, argmax, 1);
+ ag.keys = arr_get_arrval(avtarget, argmax, 2);
+ ag.limit = arr_get_intval(avtarget, argmax, 3);
+ ag.skip = arr_get_intval(avtarget, argmax, 4);
+ ag.modop = arr_get_strval(avtarget, argmax, 5);
+ ag.modvals = arr_get_arrval(avtarget, argmax, 6);
+ ag.filters = arr_get_arrval(avtarget, argmax, 7);
+ ag.invalues_keypart = arr_get_intval(avtarget, argmax, 8, -1);
+ ag.invalues = arr_get_arrval(avtarget, argmax, 9);
+ DBG(fprintf(stderr, "execute_multi3 %d: %d %s %p %d %d %s %p %p %d %p\n",
+ i, ag.id, ag.op, ag.keys, ag.limit, ag.skip, ag.modop, ag.modvals,
+ ag.filters, ag.invalues_keypart, ag.invalues));
+ }
+ RETVAL = execute_multi_internal(obj, args, cmdsmax + 1);
+ sv_2mortal((SV *)RETVAL);
+OUTPUT:
+ RETVAL
+
+AV *
+execute_find(obj, id, op, keys, limit, skip, mop = 0, mvs = 0, fils = 0, ivkeypart = -1, ivs = 0)
+ SV *obj
+ int id
+ const char *op
+ AV *keys
+ int limit
+ int skip
+ SV *mop
+ SV *mvs
+ SV *fils
+ int ivkeypart
+ SV *ivs
+CODE:
+ const char *const mop_str = sv_get_strval(mop);
+ AV *const mvs_av = sv_get_arrval(mvs);
+ AV *const fils_av = sv_get_arrval(fils);
+ AV *const ivs_av = sv_get_arrval(ivs);
+ RETVAL = execute_internal(obj, id, op, keys, limit, skip, mop_str, mvs_av,
+ fils_av, ivkeypart, ivs_av);
+ sv_2mortal((SV *)RETVAL);
+OUTPUT:
+ RETVAL
+
+AV *
+execute_update(obj, id, op, keys, limit, skip, modvals, fils = 0, ivkeypart = -1, ivs = 0)
+ SV *obj
+ int id
+ const char *op
+ AV *keys
+ int limit
+ int skip
+ AV *modvals
+ SV *fils
+ int ivkeypart
+ SV *ivs
+CODE:
+ AV *const fils_av = sv_get_arrval(fils);
+ AV *const ivs_av = sv_get_arrval(ivs);
+ RETVAL = execute_internal(obj, id, op, keys, limit, skip, "U",
+ modvals, fils_av, ivkeypart, ivs_av);
+ sv_2mortal((SV *)RETVAL);
+OUTPUT:
+ RETVAL
+
+AV *
+execute_delete(obj, id, op, keys, limit, skip, fils = 0, ivkeypart = -1, ivs = 0)
+ SV *obj
+ int id
+ const char *op
+ AV *keys
+ int limit
+ int skip
+ SV *fils
+ int ivkeypart
+ SV *ivs
+CODE:
+ AV *const fils_av = sv_get_arrval(fils);
+ AV *const ivs_av = sv_get_arrval(ivs);
+ RETVAL = execute_internal(obj, id, op, keys, limit, skip, "D", 0, fils_av,
+ ivkeypart, ivs_av);
+ sv_2mortal((SV *)RETVAL);
+OUTPUT:
+ RETVAL
+
+AV *
+execute_insert(obj, id, fvals)
+ SV *obj
+ int id
+ AV *fvals
+CODE:
+ RETVAL = execute_internal(obj, id, "+", fvals, 0, 0, 0, 0, 0, -1, 0);
+ sv_2mortal((SV *)RETVAL);
+OUTPUT:
+ RETVAL
+
diff --git a/plugin/handler_socket/perl-Net-HandlerSocket/MANIFEST b/plugin/handler_socket/perl-Net-HandlerSocket/MANIFEST
new file mode 100644
index 00000000..874fadb5
--- /dev/null
+++ b/plugin/handler_socket/perl-Net-HandlerSocket/MANIFEST
@@ -0,0 +1,8 @@
+Changes
+HandlerSocket.xs
+Makefile.PL
+MANIFEST
+ppport.h
+README
+t/HandlerSocket.t
+lib/Net/HandlerSocket.pm
diff --git a/plugin/handler_socket/perl-Net-HandlerSocket/Makefile.PL.in b/plugin/handler_socket/perl-Net-HandlerSocket/Makefile.PL.in
new file mode 100644
index 00000000..1a9b1444
--- /dev/null
+++ b/plugin/handler_socket/perl-Net-HandlerSocket/Makefile.PL.in
@@ -0,0 +1,18 @@
+# use 5.010000;
+use ExtUtils::MakeMaker;
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+WriteMakefile(
+ NAME => 'Net::HandlerSocket',
+ VERSION_FROM => 'lib/Net/HandlerSocket.pm', # finds $VERSION
+ PREREQ_PM => {}, # e.g., Module::Name => 1.1
+ ($] >= 5.005 ? ## Add these new keywords supported since 5.005
+ (ABSTRACT_FROM => 'lib/Net/HandlerSocket.pm', # retrieve abstract from module
+ AUTHOR => 'higuchi dot akira at dena dot jp>') : ()),
+ CC => 'g++ -fPIC',
+ LD => 'g++ -fPIC',
+ LIBS => ['-L@builddir@/../libhsclient -L@builddir@/../libhsclient/.libs -lhsclient'],
+ DEFINE => '',
+ INC => '-I. -I../libhsclient -I@builddir@/../libhsclient -I@top_builddir@/include',
+ OPTIMIZE => '-g -O3 -Wall -Wno-unused',
+);
diff --git a/plugin/handler_socket/perl-Net-HandlerSocket/Makefile.PL.installed b/plugin/handler_socket/perl-Net-HandlerSocket/Makefile.PL.installed
new file mode 100644
index 00000000..0d01bceb
--- /dev/null
+++ b/plugin/handler_socket/perl-Net-HandlerSocket/Makefile.PL.installed
@@ -0,0 +1,20 @@
+# use 5.010000;
+use ExtUtils::MakeMaker;
+# See lib/ExtUtils/MakeMaker.pm for details of how to influence
+# the contents of the Makefile that is written.
+WriteMakefile(
+ NAME => 'Net::HandlerSocket',
+ VERSION_FROM => 'lib/Net/HandlerSocket.pm', # finds $VERSION
+ PREREQ_PM => {}, # e.g., Module::Name => 1.1
+ ($] >= 5.005 ? ## Add these new keywords supported since 5.005
+ (ABSTRACT_FROM => 'lib/Net/HandlerSocket.pm', # retrieve abstract from module
+ AUTHOR => 'higuchi dot akira at dena dot jp>') : ()),
+ CC => 'g++ -fPIC',
+ LD => 'g++ -fPIC',
+ LIBS => ['-lhsclient'], # e.g., '-lm'
+ DEFINE => '', # e.g., '-DHAVE_SOMETHING'
+ INC => '-I. -I/usr/include/handlersocket -I/usr/include/mysql',
+ OPTIMIZE => '-g -O3 -Wall -Wno-unused',
+ # Un-comment this if you add C files to link with later:
+ # OBJECT => '$(O_FILES)', # link all the C files too
+);
diff --git a/plugin/handler_socket/perl-Net-HandlerSocket/README b/plugin/handler_socket/perl-Net-HandlerSocket/README
new file mode 100644
index 00000000..b6aec952
--- /dev/null
+++ b/plugin/handler_socket/perl-Net-HandlerSocket/README
@@ -0,0 +1,30 @@
+HandlerSocket version 0.01
+==========================
+
+The README is used to introduce the module and provide instructions on
+how to install the module, any machine dependencies it may have (for
+example C compilers and installed libraries) and any other information
+that should be provided before the module is installed.
+
+A README file is required for CPAN modules since CPAN extracts the
+README file from a module distribution so that people browsing the
+archive can use it get an idea of the modules uses. It is usually a
+good idea to provide version information here so that people can
+decide whether fixes for the module are worth downloading.
+
+INSTALLATION
+
+To install this module type the following:
+
+ perl Makefile.PL
+ make
+ make test
+ make install
+
+DEPENDENCIES
+
+COPYRIGHT AND LICENCE
+
+ Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+ See COPYRIGHT.txt for details.
+
diff --git a/plugin/handler_socket/perl-Net-HandlerSocket/lib/Net/HandlerSocket.pm b/plugin/handler_socket/perl-Net-HandlerSocket/lib/Net/HandlerSocket.pm
new file mode 100644
index 00000000..f1ad5556
--- /dev/null
+++ b/plugin/handler_socket/perl-Net-HandlerSocket/lib/Net/HandlerSocket.pm
@@ -0,0 +1,68 @@
+
+package Net::HandlerSocket;
+
+use strict;
+use warnings;
+
+require Exporter;
+
+our @ISA = qw(Exporter);
+
+# Items to export into callers namespace by default. Note: do not export
+# names by default without a very good reason. Use EXPORT_OK instead.
+# Do not simply export all your public functions/methods/constants.
+
+# This allows declaration use Net::HandlerSocket ':all';
+# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
+# will save memory.
+our %EXPORT_TAGS = ( 'all' => [ qw(
+
+) ] );
+
+our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
+
+our @EXPORT = qw(
+
+);
+
+our $VERSION = '0.01';
+
+require XSLoader;
+XSLoader::load('Net::HandlerSocket', $VERSION);
+
+# Preloaded methods go here.
+
+1;
+__END__
+# Below is stub documentation for your module. You'd better edit it!
+
+=head1 NAME
+
+Net::HandlerSocket - Perl extension for blah blah blah
+
+=head1 SYNOPSIS
+
+ use Net::HandlerSocket;
+ my $hsargs = { host => 'localhost', port => 9999 };
+ my $cli = new Net::HandlerSocket($hsargs);
+ $cli->open_index(1, 'testdb', 'testtable1', 'PRIMARY', 'foo,bar,baz');
+ $cli->open_index(2, 'testdb', 'testtable2', 'i2', 'hoge,fuga');
+ $cli->execute_find(1, '>=', [ 'aaa', 'bbb' ], 5, 100);
+ # select foo,bar,baz from testdb.testtable1
+ # where pk1 = 'aaa' and pk2 = 'bbb' order by pk1, pk2
+ # limit 100, 5
+
+=head1 DESCRIPTION
+
+Stub documentation for Net::HandlerSocket, created by h2xs.
+
+=head1 AUTHOR
+
+Akira HiguchiE<lt>higuchi dot akira at dena dot jpE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
+See COPYRIGHT.txt for details.
+
+=cut
diff --git a/plugin/handler_socket/perl-Net-HandlerSocket/lib/Net/HandlerSocket/Pool.pm b/plugin/handler_socket/perl-Net-HandlerSocket/lib/Net/HandlerSocket/Pool.pm
new file mode 100755
index 00000000..b6ea6265
--- /dev/null
+++ b/plugin/handler_socket/perl-Net-HandlerSocket/lib/Net/HandlerSocket/Pool.pm
@@ -0,0 +1,362 @@
+#!/usr/bin/env perl
+
+package Net::HandlerSocket::HSPool;
+
+use strict;
+use warnings;
+use Net::HandlerSocket;
+use Socket;
+
+sub new {
+ my $self = {
+ config => $_[1],
+ reopen_interval => 60,
+ hostmap => { },
+ };
+ return bless $self, $_[0];
+}
+
+sub clear_pool {
+ my ($self) = @_;
+ $self->{hostmap} = { };
+}
+
+sub on_error {
+ my ($self, $obj) = @_;
+ my $error_func = $self->{config}->{error};
+ if (defined($error_func)) {
+ return &{$error_func}($obj);
+ }
+ die $obj;
+}
+
+sub on_warning {
+ my ($self, $obj) = @_;
+ my $warning_func = $self->{config}->{warning};
+ if (defined($warning_func)) {
+ return &{$warning_func}($obj);
+ }
+}
+
+sub get_conf {
+ my ($self, $dbtbl) = @_;
+ my $hcent = $self->{config}->{hostmap}->{$dbtbl};
+ if (!defined($hcent)) {
+ $self->on_error("get_conf: $dbtbl not found");
+ return undef;
+ }
+ my %cpy = %$hcent;
+ $cpy{port} ||= 9998;
+ $cpy{timeout} ||= 2;
+ return \%cpy;
+}
+
+sub resolve_hostname {
+ my ($self, $hcent, $host_ip_list) = @_;
+ if (defined($host_ip_list)) {
+ if (scalar(@$host_ip_list) > 0) {
+ $hcent->{host} = shift(@$host_ip_list);
+ return $host_ip_list;
+ }
+ return undef; # no more ip
+ }
+ my $host = $hcent->{host}; # unresolved name
+ $hcent->{hostname} = $host;
+ my $resolve_list_func = $self->{config}->{resolve_list};
+ if (defined($resolve_list_func)) {
+ $host_ip_list = &{$resolve_list_func}($host);
+ if (scalar(@$host_ip_list) > 0) {
+ $hcent->{host} = shift(@$host_ip_list);
+ return $host_ip_list;
+ }
+ return undef; # no more ip
+ }
+ my $resolve_func = $self->{config}->{resolve};
+ if (defined($resolve_func)) {
+ $hcent->{host} = &{$resolve_func}($host);
+ return [];
+ }
+ my $packed = gethostbyname($host);
+ if (!defined($packed)) {
+ return undef;
+ }
+ $hcent->{host} = inet_ntoa($packed);
+ return [];
+}
+
+sub get_handle_exec {
+ my ($self, $db, $tbl, $idx, $cols, $exec_multi, $exec_args) = @_;
+ my $now = time();
+ my $dbtbl = join('.', $db, $tbl);
+ my $hcent = $self->get_conf($dbtbl); # copy
+ if (!defined($hcent)) {
+ return undef;
+ }
+ my $hmkey = join(':', $hcent->{host}, $hcent->{port});
+ my $hment = $self->{hostmap}->{$hmkey};
+ # [ open_time, handle, index_map, host, next_index_id ]
+ my $host_ip_list;
+ TRY_OTHER_IP:
+ if (!defined($hment) ||
+ $hment->[0] + $self->{reopen_interval} < $now ||
+ !$hment->[1]->stable_point()) {
+ $host_ip_list = $self->resolve_hostname($hcent, $host_ip_list);
+ if (!defined($host_ip_list)) {
+ my $hostport = $hmkey . '(' . $hcent->{host} . ')';
+ $self->on_error("HSPool::get_handle" .
+ "($db, $tbl, $idx, $cols): host=$hmkey: " .
+ "no more active ip");
+ return undef;
+ }
+ my $hnd = new Net::HandlerSocket($hcent);
+ my %m = ();
+ $hment = [ $now, $hnd, \%m, $hcent->{host}, 1 ];
+ $self->{hostmap}->{$hmkey} = $hment;
+ }
+ my $hnd = $hment->[1];
+ my $idxmap = $hment->[2];
+ my $imkey = join(':', $idx, $cols);
+ my $idx_id = $idxmap->{$imkey};
+ if (!defined($idx_id)) {
+ $idx_id = $hment->[4];
+ my $e = $hnd->open_index($idx_id, $db, $tbl, $idx, $cols);
+ if ($e != 0) {
+ my $estr = $hnd->get_error();
+ my $hostport = $hmkey . '(' . $hcent->{host} . ')';
+ my $errmess = "HSPool::get_handle open_index" .
+ "($db, $tbl, $idx, $cols): host=$hostport " .
+ "err=$e($estr)";
+ $self->on_warning($errmess);
+ $hnd->close();
+ $hment = undef;
+ goto TRY_OTHER_IP;
+ }
+ $hment->[4]++;
+ $idxmap->{$imkey} = $idx_id;
+ }
+ if ($exec_multi) {
+ my $resarr;
+ for my $cmdent (@$exec_args) {
+ $cmdent->[0] = $idx_id;
+ }
+ if (scalar(@$exec_args) == 0) {
+ $resarr = [];
+ } else {
+ $resarr = $hnd->execute_multi($exec_args);
+ }
+ my $i = 0;
+ for my $res (@$resarr) {
+ if ($res->[0] != 0) {
+ my $cmdent = $exec_args->[$i];
+ my $ec = $res->[0];
+ my $estr = $res->[1];
+ my $op = $cmdent->[1];
+ my $kfvs = $cmdent->[2];
+ my $kvstr = defined($kfvs)
+ ? join(',', @$kfvs) : '';
+ my $limit = $cmdent->[3] || 0;
+ my $skip = $cmdent->[4] || 0;
+ my $hostport = $hmkey . '(' . $hcent->{host}
+ . ')';
+ my $errmess = "HSPool::get_handle execm" .
+ "($db, $tbl, $idx, [$cols], " .
+ "($idx_id), $op, [$kvstr] " .
+ "$limit, $skip): " .
+ "host=$hostport err=$ec($estr)";
+ if ($res->[0] < 0 || $res->[0] == 2) {
+ $self->on_warning($errmess);
+ $hnd->close();
+ $hment = undef;
+ goto TRY_OTHER_IP;
+ } else {
+ $self->on_error($errmess);
+ }
+ }
+ shift(@$res);
+ ++$i;
+ }
+ return $resarr;
+ } else {
+ my $res = $hnd->execute_find($idx_id, @$exec_args);
+ if ($res->[0] != 0) {
+ my ($op, $kfvals, $limit, $skip) = @$exec_args;
+ my $ec = $res->[0];
+ my $estr = $res->[1];
+ my $kvstr = join(',', @$kfvals);
+ my $hostport = $hmkey . '(' . $hcent->{host} . ')';
+ my $errmess = "HSPool::get_handle exec" .
+ "($db, $tbl, $idx, [$cols], ($idx_id), " .
+ "$op, [$kvstr], $limit, $skip): " .
+ "host=$hostport err=$ec($estr)";
+ if ($res->[0] < 0 || $res->[0] == 2) {
+ $self->on_warning($errmess);
+ $hnd->close();
+ $hment = undef;
+ goto TRY_OTHER_IP;
+ } else {
+ $self->on_error($errmess);
+ }
+ }
+ shift(@$res);
+ return $res;
+ }
+}
+
+sub index_find {
+ my ($self, $db, $tbl, $idx, $cols, $op, $kfvals, $limit, $skip) = @_;
+ # cols: comma separated list
+ # kfvals: arrayref
+ $limit ||= 0;
+ $skip ||= 0;
+ my $res = $self->get_handle_exec($db, $tbl, $idx, $cols,
+ 0, [ $op, $kfvals, $limit, $skip ]);
+ return $res;
+}
+
+sub index_find_multi {
+ my ($self, $db, $tbl, $idx, $cols, $cmdlist) = @_;
+ # cols : comma separated list
+ # cmdlist : [ dummy, op, kfvals, limit, skip ]
+ # kfvals : arrayref
+ my $resarr = $self->get_handle_exec($db, $tbl, $idx, $cols,
+ 1, $cmdlist);
+ return $resarr;
+}
+
+sub result_single_to_arrarr {
+ my ($numcols, $hsres, $ret) = @_;
+ my $hsreslen = scalar(@$hsres);
+ my $rlen = int($hsreslen / $numcols);
+ $ret = [ ] if !defined($ret);
+ my @r = ();
+ my $p = 0;
+ for (my $i = 0; $i < $rlen; ++$i) {
+ my @a = splice(@$hsres, $p, $numcols);
+ $p += $numcols;
+ push(@$ret, \@a);
+ }
+ return $ret; # arrayref of arrayrefs
+}
+
+sub result_multi_to_arrarr {
+ my ($numcols, $mhsres, $ret) = @_;
+ $ret = [ ] if !defined($ret);
+ for my $hsres (@$mhsres) {
+ my $hsreslen = scalar(@$hsres);
+ my $rlen = int($hsreslen / $numcols);
+ my $p = 0;
+ for (my $i = 0; $i < $rlen; ++$i) {
+ my @a = splice(@$hsres, $p, $numcols);
+ $p += $numcols;
+ push(@$ret, \@a);
+ }
+ }
+ return $ret; # arrayref of arrayrefs
+}
+
+sub result_single_to_hasharr {
+ my ($names, $hsres, $ret) = @_;
+ my $nameslen = scalar(@$names);
+ my $hsreslen = scalar(@$hsres);
+ my $rlen = int($hsreslen / $nameslen);
+ $ret = [ ] if !defined($ret);
+ my $p = 0;
+ for (my $i = 0; $i < $rlen; ++$i) {
+ my %h = ();
+ for (my $j = 0; $j < $nameslen; ++$j, ++$p) {
+ $h{$names->[$j]} = $hsres->[$p];
+ }
+ push(@$ret, \%h);
+ }
+ return $ret; # arrayref of hashrefs
+}
+
+sub result_multi_to_hasharr {
+ my ($names, $mhsres, $ret) = @_;
+ my $nameslen = scalar(@$names);
+ $ret = [ ] if !defined($ret);
+ for my $hsres (@$mhsres) {
+ my $hsreslen = scalar(@$hsres);
+ my $rlen = int($hsreslen / $nameslen);
+ my $p = 0;
+ for (my $i = 0; $i < $rlen; ++$i) {
+ my %h = ();
+ for (my $j = 0; $j < $nameslen; ++$j, ++$p) {
+ $h{$names->[$j]} = $hsres->[$p];
+ }
+ push(@$ret, \%h);
+ }
+ }
+ return $ret; # arrayref of hashrefs
+}
+
+sub result_single_to_hashhash {
+ my ($names, $key, $hsres, $ret) = @_;
+ my $nameslen = scalar(@$names);
+ my $hsreslen = scalar(@$hsres);
+ my $rlen = int($hsreslen / $nameslen);
+ $ret = { } if !defined($ret);
+ my $p = 0;
+ for (my $i = 0; $i < $rlen; ++$i) {
+ my %h = ();
+ for (my $j = 0; $j < $nameslen; ++$j, ++$p) {
+ $h{$names->[$j]} = $hsres->[$p];
+ }
+ my $k = $h{$key};
+ $ret->{$k} = \%h if defined($k);
+ }
+ return $ret; # hashref of hashrefs
+}
+
+sub result_multi_to_hashhash {
+ my ($names, $key, $mhsres, $ret) = @_;
+ my $nameslen = scalar(@$names);
+ $ret = { } if !defined($ret);
+ for my $hsres (@$mhsres) {
+ my $hsreslen = scalar(@$hsres);
+ my $rlen = int($hsreslen / $nameslen);
+ my $p = 0;
+ for (my $i = 0; $i < $rlen; ++$i) {
+ my %h = ();
+ for (my $j = 0; $j < $nameslen; ++$j, ++$p) {
+ $h{$names->[$j]} = $hsres->[$p];
+ }
+ my $k = $h{$key};
+ $ret->{$k} = \%h if defined($k);
+ }
+ }
+ return $ret; # hashref of hashrefs
+}
+
+sub select_cols_where_eq_aa {
+ # SELECT $cols FROM $db.$tbl WHERE $idx_key = $kv LIMIT 1
+ my ($self, $db, $tbl, $idx, $cols_aref, $kv_aref) = @_;
+ my $cols_str = join(',', @$cols_aref);
+ my $res = $self->index_find($db, $tbl, $idx, $cols_str, '=', $kv_aref);
+ return result_single_to_arrarr(scalar(@$cols_aref), $res);
+}
+
+sub select_cols_where_eq_hh {
+ # SELECT $cols FROM $db.$tbl WHERE $idx_key = $kv LIMIT 1
+ my ($self, $db, $tbl, $idx, $cols_aref, $kv_aref, $retkey) = @_;
+ my $cols_str = join(',', @$cols_aref);
+ my $res = $self->index_find($db, $tbl, $idx, $cols_str, '=', $kv_aref);
+ my $r = result_single_to_hashhash($cols_aref, $retkey, $res);
+ return $r;
+}
+
+sub select_cols_where_in_hh {
+ # SELECT $cols FROM $db.$tbl WHERE $idx_key in ($vals)
+ my ($self, $db, $tbl, $idx, $cols_aref, $vals_aref, $retkey) = @_;
+ my $cols_str = join(',', @$cols_aref);
+ my @cmdlist = ();
+ for my $v (@$vals_aref) {
+ push(@cmdlist, [ -1, '=', [ $v ] ]);
+ }
+ my $res = $self->index_find_multi($db, $tbl, $idx, $cols_str,
+ \@cmdlist);
+ return result_multi_to_hashhash($cols_aref, $retkey, $res);
+}
+
+1;
+
diff --git a/plugin/handler_socket/perl-Net-HandlerSocket/perl-Net-HandlerSocket.spec.template b/plugin/handler_socket/perl-Net-HandlerSocket/perl-Net-HandlerSocket.spec.template
new file mode 100644
index 00000000..304baf03
--- /dev/null
+++ b/plugin/handler_socket/perl-Net-HandlerSocket/perl-Net-HandlerSocket.spec.template
@@ -0,0 +1,127 @@
+#
+# - HandlerSocket -
+# This spec file was automatically generated by cpan2rpm [ver: 2.027]
+# The following arguments were used:
+# --no-sign perl-Net-HandlerSocket.tar.gz
+# For more information on cpan2rpm please visit: http://perl.arix.com/
+#
+
+%define pkgname perl-Net-HandlerSocket
+%define filelist %{pkgname}-%{version}-filelist
+%define NVR %{pkgname}-%{version}-%{release}
+%define maketest 1
+
+name: perl-Net-HandlerSocket
+summary: HandlerSocket - Perl extension for handlersocket
+version: HANDLERSOCKET_VERSION
+release: 1%{?dist}
+packager: Akira Higuchi <higuchi dot akira at dena dot jp>
+license: BSD
+group: Applications/CPAN
+group: System Environment/Libraries
+buildroot: %{_tmppath}/%{name}-%{version}-%(id -u -n)
+prefix: %(echo %{_prefix})
+source: perl-Net-HandlerSocket.tar.gz
+BuildRequires: libhsclient
+Requires: libhsclient
+Obsoletes: perl-DB-HandlerSocket
+
+%description
+Stub documentation for HandlerSocket, created by h2xs. It looks like the
+author of the extension was negligent enough to leave the stub
+unedited.
+
+#
+# This package was generated automatically with the cpan2rpm
+# utility. To get this software or for more information
+# please visit: http://perl.arix.com/
+#
+
+%prep
+%setup -q -n %{pkgname}
+chmod -R u+w %{_builddir}/%{pkgname}
+
+%build
+grep -rsl '^#!.*perl' . |
+grep -v '.bak$' |xargs --no-run-if-empty \
+%__perl -MExtUtils::MakeMaker -e 'MY->fixin(@ARGV)'
+CFLAGS="$RPM_OPT_FLAGS"
+%{__perl} Makefile.PL.installed `%{__perl} -MExtUtils::MakeMaker -e ' print qq|PREFIX=%{buildroot}%{_prefix}| if \$ExtUtils::MakeMaker::VERSION =~ /5\.9[1-6]|6\.0[0-5]/ '`
+%{__make}
+%if %maketest
+%{__make} test
+%endif
+
+%install
+[ "%{buildroot}" != "/" ] && rm -rf %{buildroot}
+
+%{makeinstall} `%{__perl} -MExtUtils::MakeMaker -e ' print \$ExtUtils::MakeMaker::VERSION <= 6.05 ? qq|PREFIX=%{buildroot}%{_prefix}| : qq|DESTDIR=%{buildroot}| '`
+
+cmd=/usr/share/spec-helper/compress_files
+[ -x $cmd ] || cmd=/usr/lib/rpm/brp-compress
+[ -x $cmd ] && $cmd
+
+# SuSE Linux
+if [ -e /etc/SuSE-release -o -e /etc/UnitedLinux-release ]
+then
+ %{__mkdir_p} %{buildroot}/var/adm/perl-modules
+ %{__cat} `find %{buildroot} -name "perllocal.pod"` \
+ | %{__sed} -e s+%{buildroot}++g \
+ > %{buildroot}/var/adm/perl-modules/%{name}
+fi
+
+# remove special files
+find %{buildroot} -name "perllocal.pod" \
+ -o -name ".packlist" \
+ -o -name "*.bs" \
+ |xargs -i rm -f {}
+
+# no empty directories
+find %{buildroot}%{_prefix} \
+ -type d -depth \
+ -exec rmdir {} \; 2>/dev/null
+
+%{__perl} -MFile::Find -le '
+ find({ wanted => \&wanted, no_chdir => 1}, "%{buildroot}");
+ print "%doc Changes README";
+ for my $x (sort @dirs, @files) {
+ push @ret, $x unless indirs($x);
+ }
+ print join "\n", sort @ret;
+
+ sub wanted {
+ return if /auto$/;
+
+ local $_ = $File::Find::name;
+ my $f = $_; s|^\Q%{buildroot}\E||;
+ return unless length;
+ return $files[@files] = $_ if -f $f;
+
+ $d = $_;
+ /\Q$d\E/ && return for reverse sort @INC;
+ $d =~ /\Q$_\E/ && return
+ for qw|/etc %_prefix/man %_prefix/bin %_prefix/share|;
+
+ $dirs[@dirs] = $_;
+ }
+
+ sub indirs {
+ my $x = shift;
+ $x =~ /^\Q$_\E\// && $x ne $_ && return 1 for @dirs;
+ }
+ ' > %filelist
+
+[ -z %filelist ] && {
+ echo "ERROR: empty %files listing"
+ exit -1
+ }
+
+%clean
+[ "%{buildroot}" != "/" ] && rm -rf %{buildroot}
+
+%files -f %filelist
+%defattr(-,root,root)
+
+%changelog
+* Thu Apr 1 2010 a@localhost.localdomain
+- Initial build.
diff --git a/plugin/handler_socket/perl-Net-HandlerSocket/ppport.h b/plugin/handler_socket/perl-Net-HandlerSocket/ppport.h
new file mode 100644
index 00000000..6e562f5b
--- /dev/null
+++ b/plugin/handler_socket/perl-Net-HandlerSocket/ppport.h
@@ -0,0 +1,6375 @@
+#if 0
+<<'SKIP';
+#endif
+/*
+----------------------------------------------------------------------
+
+ ppport.h -- Perl/Pollution/Portability Version 3.13
+
+ Automatically created by Devel::PPPort running under perl 5.010000.
+
+ Do NOT edit this file directly! -- Edit PPPort_pm.PL and the
+ includes in parts/inc/ instead.
+
+ Use 'perldoc ppport.h' to view the documentation below.
+
+----------------------------------------------------------------------
+
+SKIP
+
+=pod
+
+=head1 NAME
+
+ppport.h - Perl/Pollution/Portability version 3.13
+
+=head1 SYNOPSIS
+
+ perl ppport.h [options] [source files]
+
+ Searches current directory for files if no [source files] are given
+
+ --help show short help
+
+ --version show version
+
+ --patch=file write one patch file with changes
+ --copy=suffix write changed copies with suffix
+ --diff=program use diff program and options
+
+ --compat-version=version provide compatibility with Perl version
+ --cplusplus accept C++ comments
+
+ --quiet don't output anything except fatal errors
+ --nodiag don't show diagnostics
+ --nohints don't show hints
+ --nochanges don't suggest changes
+ --nofilter don't filter input files
+
+ --strip strip all script and doc functionality from
+ ppport.h
+
+ --list-provided list provided API
+ --list-unsupported list unsupported API
+ --api-info=name show Perl API portability information
+
+=head1 COMPATIBILITY
+
+This version of F<ppport.h> is designed to support operation with Perl
+installations back to 5.003, and has been tested up to 5.10.0.
+
+=head1 OPTIONS
+
+=head2 --help
+
+Display a brief usage summary.
+
+=head2 --version
+
+Display the version of F<ppport.h>.
+
+=head2 --patch=I<file>
+
+If this option is given, a single patch file will be created if
+any changes are suggested. This requires a working diff program
+to be installed on your system.
+
+=head2 --copy=I<suffix>
+
+If this option is given, a copy of each file will be saved with
+the given suffix that contains the suggested changes. This does
+not require any external programs. Note that this does not
+automagially add a dot between the original filename and the
+suffix. If you want the dot, you have to include it in the option
+argument.
+
+If neither C<--patch> or C<--copy> are given, the default is to
+simply print the diffs for each file. This requires either
+C<Text::Diff> or a C<diff> program to be installed.
+
+=head2 --diff=I<program>
+
+Manually set the diff program and options to use. The default
+is to use C<Text::Diff>, when installed, and output unified
+context diffs.
+
+=head2 --compat-version=I<version>
+
+Tell F<ppport.h> to check for compatibility with the given
+Perl version. The default is to check for compatibility with Perl
+version 5.003. You can use this option to reduce the output
+of F<ppport.h> if you intend to be backward compatible only
+down to a certain Perl version.
+
+=head2 --cplusplus
+
+Usually, F<ppport.h> will detect C++ style comments and
+replace them with C style comments for portability reasons.
+Using this option instructs F<ppport.h> to leave C++
+comments untouched.
+
+=head2 --quiet
+
+Be quiet. Don't print anything except fatal errors.
+
+=head2 --nodiag
+
+Don't output any diagnostic messages. Only portability
+alerts will be printed.
+
+=head2 --nohints
+
+Don't output any hints. Hints often contain useful portability
+notes. Warnings will still be displayed.
+
+=head2 --nochanges
+
+Don't suggest any changes. Only give diagnostic output and hints
+unless these are also deactivated.
+
+=head2 --nofilter
+
+Don't filter the list of input files. By default, files not looking
+like source code (i.e. not *.xs, *.c, *.cc, *.cpp or *.h) are skipped.
+
+=head2 --strip
+
+Strip all script and documentation functionality from F<ppport.h>.
+This reduces the size of F<ppport.h> dramatically and may be useful
+if you want to include F<ppport.h> in smaller modules without
+increasing their distribution size too much.
+
+The stripped F<ppport.h> will have a C<--unstrip> option that allows
+you to undo the stripping, but only if an appropriate C<Devel::PPPort>
+module is installed.
+
+=head2 --list-provided
+
+Lists the API elements for which compatibility is provided by
+F<ppport.h>. Also lists if it must be explicitly requested,
+if it has dependencies, and if there are hints or warnings for it.
+
+=head2 --list-unsupported
+
+Lists the API elements that are known not to be supported by
+F<ppport.h> and below which version of Perl they probably
+won't be available or work.
+
+=head2 --api-info=I<name>
+
+Show portability information for API elements matching I<name>.
+If I<name> is surrounded by slashes, it is interpreted as a regular
+expression.
+
+=head1 DESCRIPTION
+
+In order for a Perl extension (XS) module to be as portable as possible
+across differing versions of Perl itself, certain steps need to be taken.
+
+=over 4
+
+=item *
+
+Including this header is the first major one. This alone will give you
+access to a large part of the Perl API that hasn't been available in
+earlier Perl releases. Use
+
+ perl ppport.h --list-provided
+
+to see which API elements are provided by ppport.h.
+
+=item *
+
+You should avoid using deprecated parts of the API. For example, using
+global Perl variables without the C<PL_> prefix is deprecated. Also,
+some API functions used to have a C<perl_> prefix. Using this form is
+also deprecated. You can safely use the supported API, as F<ppport.h>
+will provide wrappers for older Perl versions.
+
+=item *
+
+If you use one of a few functions or variables that were not present in
+earlier versions of Perl, and that can't be provided using a macro, you
+have to explicitly request support for these functions by adding one or
+more C<#define>s in your source code before the inclusion of F<ppport.h>.
+
+These functions or variables will be marked C<explicit> in the list shown
+by C<--list-provided>.
+
+Depending on whether you module has a single or multiple files that
+use such functions or variables, you want either C<static> or global
+variants.
+
+For a C<static> function or variable (used only in a single source
+file), use:
+
+ #define NEED_function
+ #define NEED_variable
+
+For a global function or variable (used in multiple source files),
+use:
+
+ #define NEED_function_GLOBAL
+ #define NEED_variable_GLOBAL
+
+Note that you mustn't have more than one global request for the
+same function or variable in your project.
+
+ Function / Variable Static Request Global Request
+ -----------------------------------------------------------------------------------------
+ PL_signals NEED_PL_signals NEED_PL_signals_GLOBAL
+ eval_pv() NEED_eval_pv NEED_eval_pv_GLOBAL
+ grok_bin() NEED_grok_bin NEED_grok_bin_GLOBAL
+ grok_hex() NEED_grok_hex NEED_grok_hex_GLOBAL
+ grok_number() NEED_grok_number NEED_grok_number_GLOBAL
+ grok_numeric_radix() NEED_grok_numeric_radix NEED_grok_numeric_radix_GLOBAL
+ grok_oct() NEED_grok_oct NEED_grok_oct_GLOBAL
+ load_module() NEED_load_module NEED_load_module_GLOBAL
+ my_snprintf() NEED_my_snprintf NEED_my_snprintf_GLOBAL
+ my_strlcat() NEED_my_strlcat NEED_my_strlcat_GLOBAL
+ my_strlcpy() NEED_my_strlcpy NEED_my_strlcpy_GLOBAL
+ newCONSTSUB() NEED_newCONSTSUB NEED_newCONSTSUB_GLOBAL
+ newRV_noinc() NEED_newRV_noinc NEED_newRV_noinc_GLOBAL
+ newSVpvn_share() NEED_newSVpvn_share NEED_newSVpvn_share_GLOBAL
+ sv_2pv_flags() NEED_sv_2pv_flags NEED_sv_2pv_flags_GLOBAL
+ sv_2pvbyte() NEED_sv_2pvbyte NEED_sv_2pvbyte_GLOBAL
+ sv_catpvf_mg() NEED_sv_catpvf_mg NEED_sv_catpvf_mg_GLOBAL
+ sv_catpvf_mg_nocontext() NEED_sv_catpvf_mg_nocontext NEED_sv_catpvf_mg_nocontext_GLOBAL
+ sv_pvn_force_flags() NEED_sv_pvn_force_flags NEED_sv_pvn_force_flags_GLOBAL
+ sv_setpvf_mg() NEED_sv_setpvf_mg NEED_sv_setpvf_mg_GLOBAL
+ sv_setpvf_mg_nocontext() NEED_sv_setpvf_mg_nocontext NEED_sv_setpvf_mg_nocontext_GLOBAL
+ vload_module() NEED_vload_module NEED_vload_module_GLOBAL
+ vnewSVpvf() NEED_vnewSVpvf NEED_vnewSVpvf_GLOBAL
+ warner() NEED_warner NEED_warner_GLOBAL
+
+To avoid namespace conflicts, you can change the namespace of the
+explicitly exported functions / variables using the C<DPPP_NAMESPACE>
+macro. Just C<#define> the macro before including C<ppport.h>:
+
+ #define DPPP_NAMESPACE MyOwnNamespace_
+ #include "ppport.h"
+
+The default namespace is C<DPPP_>.
+
+=back
+
+The good thing is that most of the above can be checked by running
+F<ppport.h> on your source code. See the next section for
+details.
+
+=head1 EXAMPLES
+
+To verify whether F<ppport.h> is needed for your module, whether you
+should make any changes to your code, and whether any special defines
+should be used, F<ppport.h> can be run as a Perl script to check your
+source code. Simply say:
+
+ perl ppport.h
+
+The result will usually be a list of patches suggesting changes
+that should at least be acceptable, if not necessarily the most
+efficient solution, or a fix for all possible problems.
+
+If you know that your XS module uses features only available in
+newer Perl releases, if you're aware that it uses C++ comments,
+and if you want all suggestions as a single patch file, you could
+use something like this:
+
+ perl ppport.h --compat-version=5.6.0 --cplusplus --patch=test.diff
+
+If you only want your code to be scanned without any suggestions
+for changes, use:
+
+ perl ppport.h --nochanges
+
+You can specify a different C<diff> program or options, using
+the C<--diff> option:
+
+ perl ppport.h --diff='diff -C 10'
+
+This would output context diffs with 10 lines of context.
+
+If you want to create patched copies of your files instead, use:
+
+ perl ppport.h --copy=.new
+
+To display portability information for the C<newSVpvn> function,
+use:
+
+ perl ppport.h --api-info=newSVpvn
+
+Since the argument to C<--api-info> can be a regular expression,
+you can use
+
+ perl ppport.h --api-info=/_nomg$/
+
+to display portability information for all C<_nomg> functions or
+
+ perl ppport.h --api-info=/./
+
+to display information for all known API elements.
+
+=head1 BUGS
+
+If this version of F<ppport.h> is causing failure during
+the compilation of this module, please check if newer versions
+of either this module or C<Devel::PPPort> are available on CPAN
+before sending a bug report.
+
+If F<ppport.h> was generated using the latest version of
+C<Devel::PPPort> and is causing failure of this module, please
+file a bug report using the CPAN Request Tracker at L<http://rt.cpan.org/>.
+
+Please include the following information:
+
+=over 4
+
+=item 1.
+
+The complete output from running "perl -V"
+
+=item 2.
+
+This file.
+
+=item 3.
+
+The name and version of the module you were trying to build.
+
+=item 4.
+
+A full log of the build that failed.
+
+=item 5.
+
+Any other information that you think could be relevant.
+
+=back
+
+For the latest version of this code, please get the C<Devel::PPPort>
+module from CPAN.
+
+=head1 COPYRIGHT
+
+Version 3.x, Copyright (c) 2004-2007, Marcus Holland-Moritz.
+
+Version 2.x, Copyright (C) 2001, Paul Marquess.
+
+Version 1.x, Copyright (C) 1999, Kenneth Albanowski.
+
+This program is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=head1 SEE ALSO
+
+See L<Devel::PPPort>.
+
+=cut
+
+use strict;
+
+# Disable broken TRIE-optimization
+BEGIN { eval '${^RE_TRIE_MAXBUF} = -1' if $] >= 5.009004 && $] <= 5.009005 }
+
+my $VERSION = 3.13;
+
+my %opt = (
+ quiet => 0,
+ diag => 1,
+ hints => 1,
+ changes => 1,
+ cplusplus => 0,
+ filter => 1,
+ strip => 0,
+ version => 0,
+);
+
+my($ppport) = $0 =~ /([\w.]+)$/;
+my $LF = '(?:\r\n|[\r\n])'; # line feed
+my $HS = "[ \t]"; # horizontal whitespace
+
+# Never use C comments in this file!
+my $ccs = '/'.'*';
+my $cce = '*'.'/';
+my $rccs = quotemeta $ccs;
+my $rcce = quotemeta $cce;
+
+eval {
+ require Getopt::Long;
+ Getopt::Long::GetOptions(\%opt, qw(
+ help quiet diag! filter! hints! changes! cplusplus strip version
+ patch=s copy=s diff=s compat-version=s
+ list-provided list-unsupported api-info=s
+ )) or usage();
+};
+
+if ($@ and grep /^-/, @ARGV) {
+ usage() if "@ARGV" =~ /^--?h(?:elp)?$/;
+ die "Getopt::Long not found. Please don't use any options.\n";
+}
+
+if ($opt{version}) {
+ print "This is $0 $VERSION.\n";
+ exit 0;
+}
+
+usage() if $opt{help};
+strip() if $opt{strip};
+
+if (exists $opt{'compat-version'}) {
+ my($r,$v,$s) = eval { parse_version($opt{'compat-version'}) };
+ if ($@) {
+ die "Invalid version number format: '$opt{'compat-version'}'\n";
+ }
+ die "Only Perl 5 is supported\n" if $r != 5;
+ die "Invalid version number: $opt{'compat-version'}\n" if $v >= 1000 || $s >= 1000;
+ $opt{'compat-version'} = sprintf "%d.%03d%03d", $r, $v, $s;
+}
+else {
+ $opt{'compat-version'} = 5;
+}
+
+my %API = map { /^(\w+)\|([^|]*)\|([^|]*)\|(\w*)$/
+ ? ( $1 => {
+ ($2 ? ( base => $2 ) : ()),
+ ($3 ? ( todo => $3 ) : ()),
+ (index($4, 'v') >= 0 ? ( varargs => 1 ) : ()),
+ (index($4, 'p') >= 0 ? ( provided => 1 ) : ()),
+ (index($4, 'n') >= 0 ? ( nothxarg => 1 ) : ()),
+ } )
+ : die "invalid spec: $_" } qw(
+AvFILLp|5.004050||p
+AvFILL|||
+CLASS|||n
+CX_CURPAD_SAVE|||
+CX_CURPAD_SV|||
+CopFILEAV|5.006000||p
+CopFILEGV_set|5.006000||p
+CopFILEGV|5.006000||p
+CopFILESV|5.006000||p
+CopFILE_set|5.006000||p
+CopFILE|5.006000||p
+CopSTASHPV_set|5.006000||p
+CopSTASHPV|5.006000||p
+CopSTASH_eq|5.006000||p
+CopSTASH_set|5.006000||p
+CopSTASH|5.006000||p
+CopyD|5.009002||p
+Copy|||
+CvPADLIST|||
+CvSTASH|||
+CvWEAKOUTSIDE|||
+DEFSV|5.004050||p
+END_EXTERN_C|5.005000||p
+ENTER|||
+ERRSV|5.004050||p
+EXTEND|||
+EXTERN_C|5.005000||p
+F0convert|||n
+FREETMPS|||
+GIMME_V||5.004000|n
+GIMME|||n
+GROK_NUMERIC_RADIX|5.007002||p
+G_ARRAY|||
+G_DISCARD|||
+G_EVAL|||
+G_NOARGS|||
+G_SCALAR|||
+G_VOID||5.004000|
+GetVars|||
+GvSV|||
+Gv_AMupdate|||
+HEf_SVKEY||5.004000|
+HeHASH||5.004000|
+HeKEY||5.004000|
+HeKLEN||5.004000|
+HePV||5.004000|
+HeSVKEY_force||5.004000|
+HeSVKEY_set||5.004000|
+HeSVKEY||5.004000|
+HeVAL||5.004000|
+HvNAME|||
+INT2PTR|5.006000||p
+IN_LOCALE_COMPILETIME|5.007002||p
+IN_LOCALE_RUNTIME|5.007002||p
+IN_LOCALE|5.007002||p
+IN_PERL_COMPILETIME|5.008001||p
+IS_NUMBER_GREATER_THAN_UV_MAX|5.007002||p
+IS_NUMBER_INFINITY|5.007002||p
+IS_NUMBER_IN_UV|5.007002||p
+IS_NUMBER_NAN|5.007003||p
+IS_NUMBER_NEG|5.007002||p
+IS_NUMBER_NOT_INT|5.007002||p
+IVSIZE|5.006000||p
+IVTYPE|5.006000||p
+IVdf|5.006000||p
+LEAVE|||
+LVRET|||
+MARK|||
+MULTICALL||5.009005|
+MY_CXT_CLONE|5.009002||p
+MY_CXT_INIT|5.007003||p
+MY_CXT|5.007003||p
+MoveD|5.009002||p
+Move|||
+NOOP|5.005000||p
+NUM2PTR|5.006000||p
+NVTYPE|5.006000||p
+NVef|5.006001||p
+NVff|5.006001||p
+NVgf|5.006001||p
+Newxc|5.009003||p
+Newxz|5.009003||p
+Newx|5.009003||p
+Nullav|||
+Nullch|||
+Nullcv|||
+Nullhv|||
+Nullsv|||
+ORIGMARK|||
+PAD_BASE_SV|||
+PAD_CLONE_VARS|||
+PAD_COMPNAME_FLAGS|||
+PAD_COMPNAME_GEN_set|||
+PAD_COMPNAME_GEN|||
+PAD_COMPNAME_OURSTASH|||
+PAD_COMPNAME_PV|||
+PAD_COMPNAME_TYPE|||
+PAD_RESTORE_LOCAL|||
+PAD_SAVE_LOCAL|||
+PAD_SAVE_SETNULLPAD|||
+PAD_SETSV|||
+PAD_SET_CUR_NOSAVE|||
+PAD_SET_CUR|||
+PAD_SVl|||
+PAD_SV|||
+PERL_ABS|5.008001||p
+PERL_BCDVERSION|5.009005||p
+PERL_GCC_BRACE_GROUPS_FORBIDDEN|5.008001||p
+PERL_HASH|5.004000||p
+PERL_INT_MAX|5.004000||p
+PERL_INT_MIN|5.004000||p
+PERL_LONG_MAX|5.004000||p
+PERL_LONG_MIN|5.004000||p
+PERL_MAGIC_arylen|5.007002||p
+PERL_MAGIC_backref|5.007002||p
+PERL_MAGIC_bm|5.007002||p
+PERL_MAGIC_collxfrm|5.007002||p
+PERL_MAGIC_dbfile|5.007002||p
+PERL_MAGIC_dbline|5.007002||p
+PERL_MAGIC_defelem|5.007002||p
+PERL_MAGIC_envelem|5.007002||p
+PERL_MAGIC_env|5.007002||p
+PERL_MAGIC_ext|5.007002||p
+PERL_MAGIC_fm|5.007002||p
+PERL_MAGIC_glob|5.009005||p
+PERL_MAGIC_isaelem|5.007002||p
+PERL_MAGIC_isa|5.007002||p
+PERL_MAGIC_mutex|5.009005||p
+PERL_MAGIC_nkeys|5.007002||p
+PERL_MAGIC_overload_elem|5.007002||p
+PERL_MAGIC_overload_table|5.007002||p
+PERL_MAGIC_overload|5.007002||p
+PERL_MAGIC_pos|5.007002||p
+PERL_MAGIC_qr|5.007002||p
+PERL_MAGIC_regdata|5.007002||p
+PERL_MAGIC_regdatum|5.007002||p
+PERL_MAGIC_regex_global|5.007002||p
+PERL_MAGIC_shared_scalar|5.007003||p
+PERL_MAGIC_shared|5.007003||p
+PERL_MAGIC_sigelem|5.007002||p
+PERL_MAGIC_sig|5.007002||p
+PERL_MAGIC_substr|5.007002||p
+PERL_MAGIC_sv|5.007002||p
+PERL_MAGIC_taint|5.007002||p
+PERL_MAGIC_tiedelem|5.007002||p
+PERL_MAGIC_tiedscalar|5.007002||p
+PERL_MAGIC_tied|5.007002||p
+PERL_MAGIC_utf8|5.008001||p
+PERL_MAGIC_uvar_elem|5.007003||p
+PERL_MAGIC_uvar|5.007002||p
+PERL_MAGIC_vec|5.007002||p
+PERL_MAGIC_vstring|5.008001||p
+PERL_QUAD_MAX|5.004000||p
+PERL_QUAD_MIN|5.004000||p
+PERL_REVISION|5.006000||p
+PERL_SCAN_ALLOW_UNDERSCORES|5.007003||p
+PERL_SCAN_DISALLOW_PREFIX|5.007003||p
+PERL_SCAN_GREATER_THAN_UV_MAX|5.007003||p
+PERL_SCAN_SILENT_ILLDIGIT|5.008001||p
+PERL_SHORT_MAX|5.004000||p
+PERL_SHORT_MIN|5.004000||p
+PERL_SIGNALS_UNSAFE_FLAG|5.008001||p
+PERL_SUBVERSION|5.006000||p
+PERL_UCHAR_MAX|5.004000||p
+PERL_UCHAR_MIN|5.004000||p
+PERL_UINT_MAX|5.004000||p
+PERL_UINT_MIN|5.004000||p
+PERL_ULONG_MAX|5.004000||p
+PERL_ULONG_MIN|5.004000||p
+PERL_UNUSED_ARG|5.009003||p
+PERL_UNUSED_CONTEXT|5.009004||p
+PERL_UNUSED_DECL|5.007002||p
+PERL_UNUSED_VAR|5.007002||p
+PERL_UQUAD_MAX|5.004000||p
+PERL_UQUAD_MIN|5.004000||p
+PERL_USE_GCC_BRACE_GROUPS|5.009004||p
+PERL_USHORT_MAX|5.004000||p
+PERL_USHORT_MIN|5.004000||p
+PERL_VERSION|5.006000||p
+PL_DBsignal|5.005000||p
+PL_DBsingle|||pn
+PL_DBsub|||pn
+PL_DBtrace|||pn
+PL_Sv|5.005000||p
+PL_compiling|5.004050||p
+PL_copline|5.009005||p
+PL_curcop|5.004050||p
+PL_curstash|5.004050||p
+PL_debstash|5.004050||p
+PL_defgv|5.004050||p
+PL_diehook|5.004050||p
+PL_dirty|5.004050||p
+PL_dowarn|||pn
+PL_errgv|5.004050||p
+PL_expect|5.009005||p
+PL_hexdigit|5.005000||p
+PL_hints|5.005000||p
+PL_last_in_gv|||n
+PL_laststatval|5.005000||p
+PL_modglobal||5.005000|n
+PL_na|5.004050||pn
+PL_no_modify|5.006000||p
+PL_ofs_sv|||n
+PL_perl_destruct_level|5.004050||p
+PL_perldb|5.004050||p
+PL_ppaddr|5.006000||p
+PL_rsfp_filters|5.004050||p
+PL_rsfp|5.004050||p
+PL_rs|||n
+PL_signals|5.008001||p
+PL_stack_base|5.004050||p
+PL_stack_sp|5.004050||p
+PL_statcache|5.005000||p
+PL_stdingv|5.004050||p
+PL_sv_arenaroot|5.004050||p
+PL_sv_no|5.004050||pn
+PL_sv_undef|5.004050||pn
+PL_sv_yes|5.004050||pn
+PL_tainted|5.004050||p
+PL_tainting|5.004050||p
+POP_MULTICALL||5.009005|
+POPi|||n
+POPl|||n
+POPn|||n
+POPpbytex||5.007001|n
+POPpx||5.005030|n
+POPp|||n
+POPs|||n
+PTR2IV|5.006000||p
+PTR2NV|5.006000||p
+PTR2UV|5.006000||p
+PTR2ul|5.007001||p
+PTRV|5.006000||p
+PUSHMARK|||
+PUSH_MULTICALL||5.009005|
+PUSHi|||
+PUSHmortal|5.009002||p
+PUSHn|||
+PUSHp|||
+PUSHs|||
+PUSHu|5.004000||p
+PUTBACK|||
+PerlIO_clearerr||5.007003|
+PerlIO_close||5.007003|
+PerlIO_context_layers||5.009004|
+PerlIO_eof||5.007003|
+PerlIO_error||5.007003|
+PerlIO_fileno||5.007003|
+PerlIO_fill||5.007003|
+PerlIO_flush||5.007003|
+PerlIO_get_base||5.007003|
+PerlIO_get_bufsiz||5.007003|
+PerlIO_get_cnt||5.007003|
+PerlIO_get_ptr||5.007003|
+PerlIO_read||5.007003|
+PerlIO_seek||5.007003|
+PerlIO_set_cnt||5.007003|
+PerlIO_set_ptrcnt||5.007003|
+PerlIO_setlinebuf||5.007003|
+PerlIO_stderr||5.007003|
+PerlIO_stdin||5.007003|
+PerlIO_stdout||5.007003|
+PerlIO_tell||5.007003|
+PerlIO_unread||5.007003|
+PerlIO_write||5.007003|
+Perl_signbit||5.009005|n
+PoisonFree|5.009004||p
+PoisonNew|5.009004||p
+PoisonWith|5.009004||p
+Poison|5.008000||p
+RETVAL|||n
+Renewc|||
+Renew|||
+SAVECLEARSV|||
+SAVECOMPPAD|||
+SAVEPADSV|||
+SAVETMPS|||
+SAVE_DEFSV|5.004050||p
+SPAGAIN|||
+SP|||
+START_EXTERN_C|5.005000||p
+START_MY_CXT|5.007003||p
+STMT_END|||p
+STMT_START|||p
+STR_WITH_LEN|5.009003||p
+ST|||
+SV_CONST_RETURN|5.009003||p
+SV_COW_DROP_PV|5.008001||p
+SV_COW_SHARED_HASH_KEYS|5.009005||p
+SV_GMAGIC|5.007002||p
+SV_HAS_TRAILING_NUL|5.009004||p
+SV_IMMEDIATE_UNREF|5.007001||p
+SV_MUTABLE_RETURN|5.009003||p
+SV_NOSTEAL|5.009002||p
+SV_SMAGIC|5.009003||p
+SV_UTF8_NO_ENCODING|5.008001||p
+SVf|5.006000||p
+SVt_IV|||
+SVt_NV|||
+SVt_PVAV|||
+SVt_PVCV|||
+SVt_PVHV|||
+SVt_PVMG|||
+SVt_PV|||
+Safefree|||
+Slab_Alloc|||
+Slab_Free|||
+Slab_to_rw|||
+StructCopy|||
+SvCUR_set|||
+SvCUR|||
+SvEND|||
+SvGAMAGIC||5.006001|
+SvGETMAGIC|5.004050||p
+SvGROW|||
+SvIOK_UV||5.006000|
+SvIOK_notUV||5.006000|
+SvIOK_off|||
+SvIOK_only_UV||5.006000|
+SvIOK_only|||
+SvIOK_on|||
+SvIOKp|||
+SvIOK|||
+SvIVX|||
+SvIV_nomg|5.009001||p
+SvIV_set|||
+SvIVx|||
+SvIV|||
+SvIsCOW_shared_hash||5.008003|
+SvIsCOW||5.008003|
+SvLEN_set|||
+SvLEN|||
+SvLOCK||5.007003|
+SvMAGIC_set|5.009003||p
+SvNIOK_off|||
+SvNIOKp|||
+SvNIOK|||
+SvNOK_off|||
+SvNOK_only|||
+SvNOK_on|||
+SvNOKp|||
+SvNOK|||
+SvNVX|||
+SvNV_set|||
+SvNVx|||
+SvNV|||
+SvOK|||
+SvOOK|||
+SvPOK_off|||
+SvPOK_only_UTF8||5.006000|
+SvPOK_only|||
+SvPOK_on|||
+SvPOKp|||
+SvPOK|||
+SvPVX_const|5.009003||p
+SvPVX_mutable|5.009003||p
+SvPVX|||
+SvPV_const|5.009003||p
+SvPV_flags_const_nolen|5.009003||p
+SvPV_flags_const|5.009003||p
+SvPV_flags_mutable|5.009003||p
+SvPV_flags|5.007002||p
+SvPV_force_flags_mutable|5.009003||p
+SvPV_force_flags_nolen|5.009003||p
+SvPV_force_flags|5.007002||p
+SvPV_force_mutable|5.009003||p
+SvPV_force_nolen|5.009003||p
+SvPV_force_nomg_nolen|5.009003||p
+SvPV_force_nomg|5.007002||p
+SvPV_force|||p
+SvPV_mutable|5.009003||p
+SvPV_nolen_const|5.009003||p
+SvPV_nolen|5.006000||p
+SvPV_nomg_const_nolen|5.009003||p
+SvPV_nomg_const|5.009003||p
+SvPV_nomg|5.007002||p
+SvPV_set|||
+SvPVbyte_force||5.009002|
+SvPVbyte_nolen||5.006000|
+SvPVbytex_force||5.006000|
+SvPVbytex||5.006000|
+SvPVbyte|5.006000||p
+SvPVutf8_force||5.006000|
+SvPVutf8_nolen||5.006000|
+SvPVutf8x_force||5.006000|
+SvPVutf8x||5.006000|
+SvPVutf8||5.006000|
+SvPVx|||
+SvPV|||
+SvREFCNT_dec|||
+SvREFCNT_inc_NN|5.009004||p
+SvREFCNT_inc_simple_NN|5.009004||p
+SvREFCNT_inc_simple_void_NN|5.009004||p
+SvREFCNT_inc_simple_void|5.009004||p
+SvREFCNT_inc_simple|5.009004||p
+SvREFCNT_inc_void_NN|5.009004||p
+SvREFCNT_inc_void|5.009004||p
+SvREFCNT_inc|||p
+SvREFCNT|||
+SvROK_off|||
+SvROK_on|||
+SvROK|||
+SvRV_set|5.009003||p
+SvRV|||
+SvRXOK||5.009005|
+SvRX||5.009005|
+SvSETMAGIC|||
+SvSHARED_HASH|5.009003||p
+SvSHARE||5.007003|
+SvSTASH_set|5.009003||p
+SvSTASH|||
+SvSetMagicSV_nosteal||5.004000|
+SvSetMagicSV||5.004000|
+SvSetSV_nosteal||5.004000|
+SvSetSV|||
+SvTAINTED_off||5.004000|
+SvTAINTED_on||5.004000|
+SvTAINTED||5.004000|
+SvTAINT|||
+SvTRUE|||
+SvTYPE|||
+SvUNLOCK||5.007003|
+SvUOK|5.007001|5.006000|p
+SvUPGRADE|||
+SvUTF8_off||5.006000|
+SvUTF8_on||5.006000|
+SvUTF8||5.006000|
+SvUVXx|5.004000||p
+SvUVX|5.004000||p
+SvUV_nomg|5.009001||p
+SvUV_set|5.009003||p
+SvUVx|5.004000||p
+SvUV|5.004000||p
+SvVOK||5.008001|
+SvVSTRING_mg|5.009004||p
+THIS|||n
+UNDERBAR|5.009002||p
+UTF8_MAXBYTES|5.009002||p
+UVSIZE|5.006000||p
+UVTYPE|5.006000||p
+UVXf|5.007001||p
+UVof|5.006000||p
+UVuf|5.006000||p
+UVxf|5.006000||p
+WARN_ALL|5.006000||p
+WARN_AMBIGUOUS|5.006000||p
+WARN_ASSERTIONS|5.009005||p
+WARN_BAREWORD|5.006000||p
+WARN_CLOSED|5.006000||p
+WARN_CLOSURE|5.006000||p
+WARN_DEBUGGING|5.006000||p
+WARN_DEPRECATED|5.006000||p
+WARN_DIGIT|5.006000||p
+WARN_EXEC|5.006000||p
+WARN_EXITING|5.006000||p
+WARN_GLOB|5.006000||p
+WARN_INPLACE|5.006000||p
+WARN_INTERNAL|5.006000||p
+WARN_IO|5.006000||p
+WARN_LAYER|5.008000||p
+WARN_MALLOC|5.006000||p
+WARN_MISC|5.006000||p
+WARN_NEWLINE|5.006000||p
+WARN_NUMERIC|5.006000||p
+WARN_ONCE|5.006000||p
+WARN_OVERFLOW|5.006000||p
+WARN_PACK|5.006000||p
+WARN_PARENTHESIS|5.006000||p
+WARN_PIPE|5.006000||p
+WARN_PORTABLE|5.006000||p
+WARN_PRECEDENCE|5.006000||p
+WARN_PRINTF|5.006000||p
+WARN_PROTOTYPE|5.006000||p
+WARN_QW|5.006000||p
+WARN_RECURSION|5.006000||p
+WARN_REDEFINE|5.006000||p
+WARN_REGEXP|5.006000||p
+WARN_RESERVED|5.006000||p
+WARN_SEMICOLON|5.006000||p
+WARN_SEVERE|5.006000||p
+WARN_SIGNAL|5.006000||p
+WARN_SUBSTR|5.006000||p
+WARN_SYNTAX|5.006000||p
+WARN_TAINT|5.006000||p
+WARN_THREADS|5.008000||p
+WARN_UNINITIALIZED|5.006000||p
+WARN_UNOPENED|5.006000||p
+WARN_UNPACK|5.006000||p
+WARN_UNTIE|5.006000||p
+WARN_UTF8|5.006000||p
+WARN_VOID|5.006000||p
+XCPT_CATCH|5.009002||p
+XCPT_RETHROW|5.009002||p
+XCPT_TRY_END|5.009002||p
+XCPT_TRY_START|5.009002||p
+XPUSHi|||
+XPUSHmortal|5.009002||p
+XPUSHn|||
+XPUSHp|||
+XPUSHs|||
+XPUSHu|5.004000||p
+XSRETURN_EMPTY|||
+XSRETURN_IV|||
+XSRETURN_NO|||
+XSRETURN_NV|||
+XSRETURN_PV|||
+XSRETURN_UNDEF|||
+XSRETURN_UV|5.008001||p
+XSRETURN_YES|||
+XSRETURN|||p
+XST_mIV|||
+XST_mNO|||
+XST_mNV|||
+XST_mPV|||
+XST_mUNDEF|||
+XST_mUV|5.008001||p
+XST_mYES|||
+XS_VERSION_BOOTCHECK|||
+XS_VERSION|||
+XSprePUSH|5.006000||p
+XS|||
+ZeroD|5.009002||p
+Zero|||
+_aMY_CXT|5.007003||p
+_pMY_CXT|5.007003||p
+aMY_CXT_|5.007003||p
+aMY_CXT|5.007003||p
+aTHXR_|5.009005||p
+aTHXR|5.009005||p
+aTHX_|5.006000||p
+aTHX|5.006000||p
+add_data|||n
+addmad|||
+allocmy|||
+amagic_call|||
+amagic_cmp_locale|||
+amagic_cmp|||
+amagic_i_ncmp|||
+amagic_ncmp|||
+any_dup|||
+ao|||
+append_elem|||
+append_list|||
+append_madprops|||
+apply_attrs_my|||
+apply_attrs_string||5.006001|
+apply_attrs|||
+apply|||
+atfork_lock||5.007003|n
+atfork_unlock||5.007003|n
+av_arylen_p||5.009003|
+av_clear|||
+av_create_and_push||5.009005|
+av_create_and_unshift_one||5.009005|
+av_delete||5.006000|
+av_exists||5.006000|
+av_extend|||
+av_fake|||
+av_fetch|||
+av_fill|||
+av_len|||
+av_make|||
+av_pop|||
+av_push|||
+av_reify|||
+av_shift|||
+av_store|||
+av_undef|||
+av_unshift|||
+ax|||n
+bad_type|||
+bind_match|||
+block_end|||
+block_gimme||5.004000|
+block_start|||
+boolSV|5.004000||p
+boot_core_PerlIO|||
+boot_core_UNIVERSAL|||
+boot_core_mro|||
+boot_core_xsutils|||
+bytes_from_utf8||5.007001|
+bytes_to_uni|||n
+bytes_to_utf8||5.006001|
+call_argv|5.006000||p
+call_atexit||5.006000|
+call_list||5.004000|
+call_method|5.006000||p
+call_pv|5.006000||p
+call_sv|5.006000||p
+calloc||5.007002|n
+cando|||
+cast_i32||5.006000|
+cast_iv||5.006000|
+cast_ulong||5.006000|
+cast_uv||5.006000|
+check_type_and_open|||
+check_uni|||
+checkcomma|||
+checkposixcc|||
+ckWARN|5.006000||p
+ck_anoncode|||
+ck_bitop|||
+ck_concat|||
+ck_defined|||
+ck_delete|||
+ck_die|||
+ck_eof|||
+ck_eval|||
+ck_exec|||
+ck_exists|||
+ck_exit|||
+ck_ftst|||
+ck_fun|||
+ck_glob|||
+ck_grep|||
+ck_index|||
+ck_join|||
+ck_lengthconst|||
+ck_lfun|||
+ck_listiob|||
+ck_match|||
+ck_method|||
+ck_null|||
+ck_open|||
+ck_readline|||
+ck_repeat|||
+ck_require|||
+ck_retarget|||
+ck_return|||
+ck_rfun|||
+ck_rvconst|||
+ck_sassign|||
+ck_select|||
+ck_shift|||
+ck_sort|||
+ck_spair|||
+ck_split|||
+ck_subr|||
+ck_substr|||
+ck_svconst|||
+ck_trunc|||
+ck_unpack|||
+ckwarn_d||5.009003|
+ckwarn||5.009003|
+cl_and|||n
+cl_anything|||n
+cl_init_zero|||n
+cl_init|||n
+cl_is_anything|||n
+cl_or|||n
+clear_placeholders|||
+closest_cop|||
+convert|||
+cop_free|||
+cr_textfilter|||
+create_eval_scope|||
+croak_nocontext|||vn
+croak|||v
+csighandler||5.009003|n
+curmad|||
+custom_op_desc||5.007003|
+custom_op_name||5.007003|
+cv_ckproto_len|||
+cv_ckproto|||
+cv_clone|||
+cv_const_sv||5.004000|
+cv_dump|||
+cv_undef|||
+cx_dump||5.005000|
+cx_dup|||
+cxinc|||
+dAXMARK|5.009003||p
+dAX|5.007002||p
+dITEMS|5.007002||p
+dMARK|||
+dMULTICALL||5.009003|
+dMY_CXT_SV|5.007003||p
+dMY_CXT|5.007003||p
+dNOOP|5.006000||p
+dORIGMARK|||
+dSP|||
+dTHR|5.004050||p
+dTHXR|5.009005||p
+dTHXa|5.006000||p
+dTHXoa|5.006000||p
+dTHX|5.006000||p
+dUNDERBAR|5.009002||p
+dVAR|5.009003||p
+dXCPT|5.009002||p
+dXSARGS|||
+dXSI32|||
+dXSTARG|5.006000||p
+deb_curcv|||
+deb_nocontext|||vn
+deb_stack_all|||
+deb_stack_n|||
+debop||5.005000|
+debprofdump||5.005000|
+debprof|||
+debstackptrs||5.007003|
+debstack||5.007003|
+debug_start_match|||
+deb||5.007003|v
+del_sv|||
+delete_eval_scope|||
+delimcpy||5.004000|
+deprecate_old|||
+deprecate|||
+despatch_signals||5.007001|
+destroy_matcher|||
+die_nocontext|||vn
+die_where|||
+die|||v
+dirp_dup|||
+div128|||
+djSP|||
+do_aexec5|||
+do_aexec|||
+do_aspawn|||
+do_binmode||5.004050|
+do_chomp|||
+do_chop|||
+do_close|||
+do_dump_pad|||
+do_eof|||
+do_exec3|||
+do_execfree|||
+do_exec|||
+do_gv_dump||5.006000|
+do_gvgv_dump||5.006000|
+do_hv_dump||5.006000|
+do_ipcctl|||
+do_ipcget|||
+do_join|||
+do_kv|||
+do_magic_dump||5.006000|
+do_msgrcv|||
+do_msgsnd|||
+do_oddball|||
+do_op_dump||5.006000|
+do_op_xmldump|||
+do_open9||5.006000|
+do_openn||5.007001|
+do_open||5.004000|
+do_pipe|||
+do_pmop_dump||5.006000|
+do_pmop_xmldump|||
+do_print|||
+do_readline|||
+do_seek|||
+do_semop|||
+do_shmio|||
+do_smartmatch|||
+do_spawn_nowait|||
+do_spawn|||
+do_sprintf|||
+do_sv_dump||5.006000|
+do_sysseek|||
+do_tell|||
+do_trans_complex_utf8|||
+do_trans_complex|||
+do_trans_count_utf8|||
+do_trans_count|||
+do_trans_simple_utf8|||
+do_trans_simple|||
+do_trans|||
+do_vecget|||
+do_vecset|||
+do_vop|||
+docatch_body|||
+docatch|||
+doeval|||
+dofile|||
+dofindlabel|||
+doform|||
+doing_taint||5.008001|n
+dooneliner|||
+doopen_pm|||
+doparseform|||
+dopoptoeval|||
+dopoptogiven|||
+dopoptolabel|||
+dopoptoloop|||
+dopoptosub_at|||
+dopoptosub|||
+dopoptowhen|||
+doref||5.009003|
+dounwind|||
+dowantarray|||
+dump_all||5.006000|
+dump_eval||5.006000|
+dump_exec_pos|||
+dump_fds|||
+dump_form||5.006000|
+dump_indent||5.006000|v
+dump_mstats|||
+dump_packsubs||5.006000|
+dump_sub||5.006000|
+dump_sv_child|||
+dump_trie_interim_list|||
+dump_trie_interim_table|||
+dump_trie|||
+dump_vindent||5.006000|
+dumpuntil|||
+dup_attrlist|||
+emulate_cop_io|||
+emulate_eaccess|||
+eval_pv|5.006000||p
+eval_sv|5.006000||p
+exec_failed|||
+expect_number|||
+fbm_compile||5.005000|
+fbm_instr||5.005000|
+fd_on_nosuid_fs|||
+feature_is_enabled|||
+filter_add|||
+filter_del|||
+filter_gets|||
+filter_read|||
+find_and_forget_pmops|||
+find_array_subscript|||
+find_beginning|||
+find_byclass|||
+find_hash_subscript|||
+find_in_my_stash|||
+find_runcv||5.008001|
+find_rundefsvoffset||5.009002|
+find_script|||
+find_uninit_var|||
+first_symbol|||n
+fold_constants|||
+forbid_setid|||
+force_ident|||
+force_list|||
+force_next|||
+force_version|||
+force_word|||
+forget_pmop|||
+form_nocontext|||vn
+form||5.004000|v
+fp_dup|||
+fprintf_nocontext|||vn
+free_global_struct|||
+free_tied_hv_pool|||
+free_tmps|||
+gen_constant_list|||
+get_arena|||
+get_av|5.006000||p
+get_context||5.006000|n
+get_cvn_flags||5.009005|
+get_cv|5.006000||p
+get_db_sub|||
+get_debug_opts|||
+get_hash_seed|||
+get_hv|5.006000||p
+get_mstats|||
+get_no_modify|||
+get_num|||
+get_op_descs||5.005000|
+get_op_names||5.005000|
+get_opargs|||
+get_ppaddr||5.006000|
+get_re_arg|||
+get_sv|5.006000||p
+get_vtbl||5.005030|
+getcwd_sv||5.007002|
+getenv_len|||
+glob_2number|||
+glob_2pv|||
+glob_assign_glob|||
+glob_assign_ref|||
+gp_dup|||
+gp_free|||
+gp_ref|||
+grok_bin|5.007003||p
+grok_hex|5.007003||p
+grok_number|5.007002||p
+grok_numeric_radix|5.007002||p
+grok_oct|5.007003||p
+group_end|||
+gv_AVadd|||
+gv_HVadd|||
+gv_IOadd|||
+gv_SVadd|||
+gv_autoload4||5.004000|
+gv_check|||
+gv_const_sv||5.009003|
+gv_dump||5.006000|
+gv_efullname3||5.004000|
+gv_efullname4||5.006001|
+gv_efullname|||
+gv_ename|||
+gv_fetchfile_flags||5.009005|
+gv_fetchfile|||
+gv_fetchmeth_autoload||5.007003|
+gv_fetchmethod_autoload||5.004000|
+gv_fetchmethod|||
+gv_fetchmeth|||
+gv_fetchpvn_flags||5.009002|
+gv_fetchpv|||
+gv_fetchsv||5.009002|
+gv_fullname3||5.004000|
+gv_fullname4||5.006001|
+gv_fullname|||
+gv_handler||5.007001|
+gv_init_sv|||
+gv_init|||
+gv_name_set||5.009004|
+gv_stashpvn|5.004000||p
+gv_stashpvs||5.009003|
+gv_stashpv|||
+gv_stashsv|||
+he_dup|||
+hek_dup|||
+hfreeentries|||
+hsplit|||
+hv_assert||5.009005|
+hv_auxinit|||n
+hv_backreferences_p|||
+hv_clear_placeholders||5.009001|
+hv_clear|||
+hv_copy_hints_hv|||
+hv_delayfree_ent||5.004000|
+hv_delete_common|||
+hv_delete_ent||5.004000|
+hv_delete|||
+hv_eiter_p||5.009003|
+hv_eiter_set||5.009003|
+hv_exists_ent||5.004000|
+hv_exists|||
+hv_fetch_common|||
+hv_fetch_ent||5.004000|
+hv_fetchs|5.009003||p
+hv_fetch|||
+hv_free_ent||5.004000|
+hv_iterinit|||
+hv_iterkeysv||5.004000|
+hv_iterkey|||
+hv_iternext_flags||5.008000|
+hv_iternextsv|||
+hv_iternext|||
+hv_iterval|||
+hv_kill_backrefs|||
+hv_ksplit||5.004000|
+hv_magic_check|||n
+hv_magic_uvar_xkey|||
+hv_magic|||
+hv_name_set||5.009003|
+hv_notallowed|||
+hv_placeholders_get||5.009003|
+hv_placeholders_p||5.009003|
+hv_placeholders_set||5.009003|
+hv_riter_p||5.009003|
+hv_riter_set||5.009003|
+hv_scalar||5.009001|
+hv_store_ent||5.004000|
+hv_store_flags||5.008000|
+hv_stores|5.009004||p
+hv_store|||
+hv_undef|||
+ibcmp_locale||5.004000|
+ibcmp_utf8||5.007003|
+ibcmp|||
+incl_perldb|||
+incline|||
+incpush_if_exists|||
+incpush|||
+ingroup|||
+init_argv_symbols|||
+init_debugger|||
+init_global_struct|||
+init_i18nl10n||5.006000|
+init_i18nl14n||5.006000|
+init_ids|||
+init_interp|||
+init_main_stash|||
+init_perllib|||
+init_postdump_symbols|||
+init_predump_symbols|||
+init_stacks||5.005000|
+init_tm||5.007002|
+instr|||
+intro_my|||
+intuit_method|||
+intuit_more|||
+invert|||
+io_close|||
+isALNUM|||
+isALPHA|||
+isDIGIT|||
+isLOWER|||
+isSPACE|||
+isUPPER|||
+is_an_int|||
+is_gv_magical_sv|||
+is_gv_magical|||
+is_handle_constructor|||n
+is_list_assignment|||
+is_lvalue_sub||5.007001|
+is_uni_alnum_lc||5.006000|
+is_uni_alnumc_lc||5.006000|
+is_uni_alnumc||5.006000|
+is_uni_alnum||5.006000|
+is_uni_alpha_lc||5.006000|
+is_uni_alpha||5.006000|
+is_uni_ascii_lc||5.006000|
+is_uni_ascii||5.006000|
+is_uni_cntrl_lc||5.006000|
+is_uni_cntrl||5.006000|
+is_uni_digit_lc||5.006000|
+is_uni_digit||5.006000|
+is_uni_graph_lc||5.006000|
+is_uni_graph||5.006000|
+is_uni_idfirst_lc||5.006000|
+is_uni_idfirst||5.006000|
+is_uni_lower_lc||5.006000|
+is_uni_lower||5.006000|
+is_uni_print_lc||5.006000|
+is_uni_print||5.006000|
+is_uni_punct_lc||5.006000|
+is_uni_punct||5.006000|
+is_uni_space_lc||5.006000|
+is_uni_space||5.006000|
+is_uni_upper_lc||5.006000|
+is_uni_upper||5.006000|
+is_uni_xdigit_lc||5.006000|
+is_uni_xdigit||5.006000|
+is_utf8_alnumc||5.006000|
+is_utf8_alnum||5.006000|
+is_utf8_alpha||5.006000|
+is_utf8_ascii||5.006000|
+is_utf8_char_slow|||n
+is_utf8_char||5.006000|
+is_utf8_cntrl||5.006000|
+is_utf8_common|||
+is_utf8_digit||5.006000|
+is_utf8_graph||5.006000|
+is_utf8_idcont||5.008000|
+is_utf8_idfirst||5.006000|
+is_utf8_lower||5.006000|
+is_utf8_mark||5.006000|
+is_utf8_print||5.006000|
+is_utf8_punct||5.006000|
+is_utf8_space||5.006000|
+is_utf8_string_loclen||5.009003|
+is_utf8_string_loc||5.008001|
+is_utf8_string||5.006001|
+is_utf8_upper||5.006000|
+is_utf8_xdigit||5.006000|
+isa_lookup|||
+items|||n
+ix|||n
+jmaybe|||
+join_exact|||
+keyword|||
+leave_scope|||
+lex_end|||
+lex_start|||
+linklist|||
+listkids|||
+list|||
+load_module_nocontext|||vn
+load_module|5.006000||pv
+localize|||
+looks_like_bool|||
+looks_like_number|||
+lop|||
+mPUSHi|5.009002||p
+mPUSHn|5.009002||p
+mPUSHp|5.009002||p
+mPUSHu|5.009002||p
+mXPUSHi|5.009002||p
+mXPUSHn|5.009002||p
+mXPUSHp|5.009002||p
+mXPUSHu|5.009002||p
+mad_free|||
+madlex|||
+madparse|||
+magic_clear_all_env|||
+magic_clearenv|||
+magic_clearhint|||
+magic_clearpack|||
+magic_clearsig|||
+magic_dump||5.006000|
+magic_existspack|||
+magic_freearylen_p|||
+magic_freeovrld|||
+magic_freeregexp|||
+magic_getarylen|||
+magic_getdefelem|||
+magic_getnkeys|||
+magic_getpack|||
+magic_getpos|||
+magic_getsig|||
+magic_getsubstr|||
+magic_gettaint|||
+magic_getuvar|||
+magic_getvec|||
+magic_get|||
+magic_killbackrefs|||
+magic_len|||
+magic_methcall|||
+magic_methpack|||
+magic_nextpack|||
+magic_regdata_cnt|||
+magic_regdatum_get|||
+magic_regdatum_set|||
+magic_scalarpack|||
+magic_set_all_env|||
+magic_setamagic|||
+magic_setarylen|||
+magic_setbm|||
+magic_setcollxfrm|||
+magic_setdbline|||
+magic_setdefelem|||
+magic_setenv|||
+magic_setfm|||
+magic_setglob|||
+magic_sethint|||
+magic_setisa|||
+magic_setmglob|||
+magic_setnkeys|||
+magic_setpack|||
+magic_setpos|||
+magic_setregexp|||
+magic_setsig|||
+magic_setsubstr|||
+magic_settaint|||
+magic_setutf8|||
+magic_setuvar|||
+magic_setvec|||
+magic_set|||
+magic_sizepack|||
+magic_wipepack|||
+magicname|||
+make_matcher|||
+make_trie_failtable|||
+make_trie|||
+malloced_size|||n
+malloc||5.007002|n
+markstack_grow|||
+matcher_matches_sv|||
+measure_struct|||
+memEQ|5.004000||p
+memNE|5.004000||p
+mem_collxfrm|||
+mess_alloc|||
+mess_nocontext|||vn
+mess||5.006000|v
+method_common|||
+mfree||5.007002|n
+mg_clear|||
+mg_copy|||
+mg_dup|||
+mg_find|||
+mg_free|||
+mg_get|||
+mg_length||5.005000|
+mg_localize|||
+mg_magical|||
+mg_set|||
+mg_size||5.005000|
+mini_mktime||5.007002|
+missingterm|||
+mode_from_discipline|||
+modkids|||
+mod|||
+more_bodies|||
+more_sv|||
+moreswitches|||
+mro_get_linear_isa_c3||5.009005|
+mro_get_linear_isa_dfs||5.009005|
+mro_get_linear_isa||5.009005|
+mro_isa_changed_in|||
+mro_meta_dup|||
+mro_meta_init|||
+mro_method_changed_in||5.009005|
+mul128|||
+mulexp10|||n
+my_atof2||5.007002|
+my_atof||5.006000|
+my_attrs|||
+my_bcopy|||n
+my_betoh16|||n
+my_betoh32|||n
+my_betoh64|||n
+my_betohi|||n
+my_betohl|||n
+my_betohs|||n
+my_bzero|||n
+my_chsize|||
+my_clearenv|||
+my_cxt_index|||
+my_cxt_init|||
+my_dirfd||5.009005|
+my_exit_jump|||
+my_exit|||
+my_failure_exit||5.004000|
+my_fflush_all||5.006000|
+my_fork||5.007003|n
+my_htobe16|||n
+my_htobe32|||n
+my_htobe64|||n
+my_htobei|||n
+my_htobel|||n
+my_htobes|||n
+my_htole16|||n
+my_htole32|||n
+my_htole64|||n
+my_htolei|||n
+my_htolel|||n
+my_htoles|||n
+my_htonl|||
+my_kid|||
+my_letoh16|||n
+my_letoh32|||n
+my_letoh64|||n
+my_letohi|||n
+my_letohl|||n
+my_letohs|||n
+my_lstat|||
+my_memcmp||5.004000|n
+my_memset|||n
+my_ntohl|||
+my_pclose||5.004000|
+my_popen_list||5.007001|
+my_popen||5.004000|
+my_setenv|||
+my_snprintf|5.009004||pvn
+my_socketpair||5.007003|n
+my_sprintf||5.009003|vn
+my_stat|||
+my_strftime||5.007002|
+my_strlcat|5.009004||pn
+my_strlcpy|5.009004||pn
+my_swabn|||n
+my_swap|||
+my_unexec|||
+my_vsnprintf||5.009004|n
+my|||
+need_utf8|||n
+newANONATTRSUB||5.006000|
+newANONHASH|||
+newANONLIST|||
+newANONSUB|||
+newASSIGNOP|||
+newATTRSUB||5.006000|
+newAVREF|||
+newAV|||
+newBINOP|||
+newCONDOP|||
+newCONSTSUB|5.004050||p
+newCVREF|||
+newDEFSVOP|||
+newFORM|||
+newFOROP|||
+newGIVENOP||5.009003|
+newGIVWHENOP|||
+newGP|||
+newGVOP|||
+newGVREF|||
+newGVgen|||
+newHVREF|||
+newHVhv||5.005000|
+newHV|||
+newIO|||
+newLISTOP|||
+newLOGOP|||
+newLOOPEX|||
+newLOOPOP|||
+newMADPROP|||
+newMADsv|||
+newMYSUB|||
+newNULLLIST|||
+newOP|||
+newPADOP|||
+newPMOP|||
+newPROG|||
+newPVOP|||
+newRANGE|||
+newRV_inc|5.004000||p
+newRV_noinc|5.004000||p
+newRV|||
+newSLICEOP|||
+newSTATEOP|||
+newSUB|||
+newSVOP|||
+newSVREF|||
+newSV_type||5.009005|
+newSVhek||5.009003|
+newSViv|||
+newSVnv|||
+newSVpvf_nocontext|||vn
+newSVpvf||5.004000|v
+newSVpvn_share|5.007001||p
+newSVpvn|5.004050||p
+newSVpvs_share||5.009003|
+newSVpvs|5.009003||p
+newSVpv|||
+newSVrv|||
+newSVsv|||
+newSVuv|5.006000||p
+newSV|||
+newTOKEN|||
+newUNOP|||
+newWHENOP||5.009003|
+newWHILEOP||5.009003|
+newXS_flags||5.009004|
+newXSproto||5.006000|
+newXS||5.006000|
+new_collate||5.006000|
+new_constant|||
+new_ctype||5.006000|
+new_he|||
+new_logop|||
+new_numeric||5.006000|
+new_stackinfo||5.005000|
+new_version||5.009000|
+new_warnings_bitfield|||
+next_symbol|||
+nextargv|||
+nextchar|||
+ninstr|||
+no_bareword_allowed|||
+no_fh_allowed|||
+no_op|||
+not_a_number|||
+nothreadhook||5.008000|
+nuke_stacks|||
+num_overflow|||n
+offer_nice_chunk|||
+oopsAV|||
+oopsCV|||
+oopsHV|||
+op_clear|||
+op_const_sv|||
+op_dump||5.006000|
+op_free|||
+op_getmad_weak|||
+op_getmad|||
+op_null||5.007002|
+op_refcnt_dec|||
+op_refcnt_inc|||
+op_refcnt_lock||5.009002|
+op_refcnt_unlock||5.009002|
+op_xmldump|||
+open_script|||
+pMY_CXT_|5.007003||p
+pMY_CXT|5.007003||p
+pTHX_|5.006000||p
+pTHX|5.006000||p
+packWARN|5.007003||p
+pack_cat||5.007003|
+pack_rec|||
+package|||
+packlist||5.008001|
+pad_add_anon|||
+pad_add_name|||
+pad_alloc|||
+pad_block_start|||
+pad_check_dup|||
+pad_compname_type|||
+pad_findlex|||
+pad_findmy|||
+pad_fixup_inner_anons|||
+pad_free|||
+pad_leavemy|||
+pad_new|||
+pad_peg|||n
+pad_push|||
+pad_reset|||
+pad_setsv|||
+pad_sv||5.009005|
+pad_swipe|||
+pad_tidy|||
+pad_undef|||
+parse_body|||
+parse_unicode_opts|||
+parser_dup|||
+parser_free|||
+path_is_absolute|||n
+peep|||
+pending_Slabs_to_ro|||
+perl_alloc_using|||n
+perl_alloc|||n
+perl_clone_using|||n
+perl_clone|||n
+perl_construct|||n
+perl_destruct||5.007003|n
+perl_free|||n
+perl_parse||5.006000|n
+perl_run|||n
+pidgone|||
+pm_description|||
+pmflag|||
+pmop_dump||5.006000|
+pmop_xmldump|||
+pmruntime|||
+pmtrans|||
+pop_scope|||
+pregcomp||5.009005|
+pregexec|||
+pregfree|||
+prepend_elem|||
+prepend_madprops|||
+printbuf|||
+printf_nocontext|||vn
+process_special_blocks|||
+ptr_table_clear||5.009005|
+ptr_table_fetch||5.009005|
+ptr_table_find|||n
+ptr_table_free||5.009005|
+ptr_table_new||5.009005|
+ptr_table_split||5.009005|
+ptr_table_store||5.009005|
+push_scope|||
+put_byte|||
+pv_display||5.006000|
+pv_escape||5.009004|
+pv_pretty||5.009004|
+pv_uni_display||5.007003|
+qerror|||
+qsortsvu|||
+re_compile||5.009005|
+re_croak2|||
+re_dup|||
+re_intuit_start||5.009005|
+re_intuit_string||5.006000|
+readpipe_override|||
+realloc||5.007002|n
+reentrant_free|||
+reentrant_init|||
+reentrant_retry|||vn
+reentrant_size|||
+ref_array_or_hash|||
+refcounted_he_chain_2hv|||
+refcounted_he_fetch|||
+refcounted_he_free|||
+refcounted_he_new|||
+refcounted_he_value|||
+refkids|||
+refto|||
+ref||5.009003|
+reg_check_named_buff_matched|||
+reg_named_buff_all||5.009005|
+reg_named_buff_exists||5.009005|
+reg_named_buff_fetch||5.009005|
+reg_named_buff_firstkey||5.009005|
+reg_named_buff_iter|||
+reg_named_buff_nextkey||5.009005|
+reg_named_buff_scalar||5.009005|
+reg_named_buff|||
+reg_namedseq|||
+reg_node|||
+reg_numbered_buff_fetch|||
+reg_numbered_buff_length|||
+reg_numbered_buff_store|||
+reg_qr_package|||
+reg_recode|||
+reg_scan_name|||
+reg_skipcomment|||
+reg_stringify||5.009005|
+reg_temp_copy|||
+reganode|||
+regatom|||
+regbranch|||
+regclass_swash||5.009004|
+regclass|||
+regcppop|||
+regcppush|||
+regcurly|||n
+regdump_extflags|||
+regdump||5.005000|
+regdupe_internal|||
+regexec_flags||5.005000|
+regfree_internal||5.009005|
+reghop3|||n
+reghop4|||n
+reghopmaybe3|||n
+reginclass|||
+reginitcolors||5.006000|
+reginsert|||
+regmatch|||
+regnext||5.005000|
+regpiece|||
+regpposixcc|||
+regprop|||
+regrepeat|||
+regtail_study|||
+regtail|||
+regtry|||
+reguni|||
+regwhite|||n
+reg|||
+repeatcpy|||
+report_evil_fh|||
+report_uninit|||
+require_pv||5.006000|
+require_tie_mod|||
+restore_magic|||
+rninstr|||
+rsignal_restore|||
+rsignal_save|||
+rsignal_state||5.004000|
+rsignal||5.004000|
+run_body|||
+run_user_filter|||
+runops_debug||5.005000|
+runops_standard||5.005000|
+rvpv_dup|||
+rxres_free|||
+rxres_restore|||
+rxres_save|||
+safesyscalloc||5.006000|n
+safesysfree||5.006000|n
+safesysmalloc||5.006000|n
+safesysrealloc||5.006000|n
+same_dirent|||
+save_I16||5.004000|
+save_I32|||
+save_I8||5.006000|
+save_aelem||5.004050|
+save_alloc||5.006000|
+save_aptr|||
+save_ary|||
+save_bool||5.008001|
+save_clearsv|||
+save_delete|||
+save_destructor_x||5.006000|
+save_destructor||5.006000|
+save_freeop|||
+save_freepv|||
+save_freesv|||
+save_generic_pvref||5.006001|
+save_generic_svref||5.005030|
+save_gp||5.004000|
+save_hash|||
+save_hek_flags|||n
+save_helem||5.004050|
+save_hints||5.005000|
+save_hptr|||
+save_int|||
+save_item|||
+save_iv||5.005000|
+save_lines|||
+save_list|||
+save_long|||
+save_magic|||
+save_mortalizesv||5.007001|
+save_nogv|||
+save_op|||
+save_padsv||5.007001|
+save_pptr|||
+save_re_context||5.006000|
+save_scalar_at|||
+save_scalar|||
+save_set_svflags||5.009000|
+save_shared_pvref||5.007003|
+save_sptr|||
+save_svref|||
+save_vptr||5.006000|
+savepvn|||
+savepvs||5.009003|
+savepv|||
+savesharedpvn||5.009005|
+savesharedpv||5.007003|
+savestack_grow_cnt||5.008001|
+savestack_grow|||
+savesvpv||5.009002|
+sawparens|||
+scalar_mod_type|||n
+scalarboolean|||
+scalarkids|||
+scalarseq|||
+scalarvoid|||
+scalar|||
+scan_bin||5.006000|
+scan_commit|||
+scan_const|||
+scan_formline|||
+scan_heredoc|||
+scan_hex|||
+scan_ident|||
+scan_inputsymbol|||
+scan_num||5.007001|
+scan_oct|||
+scan_pat|||
+scan_str|||
+scan_subst|||
+scan_trans|||
+scan_version||5.009001|
+scan_vstring||5.009005|
+scan_word|||
+scope|||
+screaminstr||5.005000|
+seed||5.008001|
+sequence_num|||
+sequence_tail|||
+sequence|||
+set_context||5.006000|n
+set_csh|||
+set_numeric_local||5.006000|
+set_numeric_radix||5.006000|
+set_numeric_standard||5.006000|
+setdefout|||
+setenv_getix|||
+share_hek_flags|||
+share_hek||5.004000|
+si_dup|||
+sighandler|||n
+simplify_sort|||
+skipspace0|||
+skipspace1|||
+skipspace2|||
+skipspace|||
+softref2xv|||
+sortcv_stacked|||
+sortcv_xsub|||
+sortcv|||
+sortsv_flags||5.009003|
+sortsv||5.007003|
+space_join_names_mortal|||
+ss_dup|||
+stack_grow|||
+start_force|||
+start_glob|||
+start_subparse||5.004000|
+stashpv_hvname_match||5.009005|
+stdize_locale|||
+strEQ|||
+strGE|||
+strGT|||
+strLE|||
+strLT|||
+strNE|||
+str_to_version||5.006000|
+strip_return|||
+strnEQ|||
+strnNE|||
+study_chunk|||
+sub_crush_depth|||
+sublex_done|||
+sublex_push|||
+sublex_start|||
+sv_2bool|||
+sv_2cv|||
+sv_2io|||
+sv_2iuv_common|||
+sv_2iuv_non_preserve|||
+sv_2iv_flags||5.009001|
+sv_2iv|||
+sv_2mortal|||
+sv_2nv|||
+sv_2pv_flags|5.007002||p
+sv_2pv_nolen|5.006000||p
+sv_2pvbyte_nolen|5.006000||p
+sv_2pvbyte|5.006000||p
+sv_2pvutf8_nolen||5.006000|
+sv_2pvutf8||5.006000|
+sv_2pv|||
+sv_2uv_flags||5.009001|
+sv_2uv|5.004000||p
+sv_add_arena|||
+sv_add_backref|||
+sv_backoff|||
+sv_bless|||
+sv_cat_decode||5.008001|
+sv_catpv_mg|5.004050||p
+sv_catpvf_mg_nocontext|||pvn
+sv_catpvf_mg|5.006000|5.004000|pv
+sv_catpvf_nocontext|||vn
+sv_catpvf||5.004000|v
+sv_catpvn_flags||5.007002|
+sv_catpvn_mg|5.004050||p
+sv_catpvn_nomg|5.007002||p
+sv_catpvn|||
+sv_catpvs|5.009003||p
+sv_catpv|||
+sv_catsv_flags||5.007002|
+sv_catsv_mg|5.004050||p
+sv_catsv_nomg|5.007002||p
+sv_catsv|||
+sv_catxmlpvn|||
+sv_catxmlsv|||
+sv_chop|||
+sv_clean_all|||
+sv_clean_objs|||
+sv_clear|||
+sv_cmp_locale||5.004000|
+sv_cmp|||
+sv_collxfrm|||
+sv_compile_2op||5.008001|
+sv_copypv||5.007003|
+sv_dec|||
+sv_del_backref|||
+sv_derived_from||5.004000|
+sv_does||5.009004|
+sv_dump|||
+sv_dup|||
+sv_eq|||
+sv_exp_grow|||
+sv_force_normal_flags||5.007001|
+sv_force_normal||5.006000|
+sv_free2|||
+sv_free_arenas|||
+sv_free|||
+sv_gets||5.004000|
+sv_grow|||
+sv_i_ncmp|||
+sv_inc|||
+sv_insert|||
+sv_isa|||
+sv_isobject|||
+sv_iv||5.005000|
+sv_kill_backrefs|||
+sv_len_utf8||5.006000|
+sv_len|||
+sv_magic_portable|5.009005|5.004000|p
+sv_magicext||5.007003|
+sv_magic|||
+sv_mortalcopy|||
+sv_ncmp|||
+sv_newmortal|||
+sv_newref|||
+sv_nolocking||5.007003|
+sv_nosharing||5.007003|
+sv_nounlocking|||
+sv_nv||5.005000|
+sv_peek||5.005000|
+sv_pos_b2u_midway|||
+sv_pos_b2u||5.006000|
+sv_pos_u2b_cached|||
+sv_pos_u2b_forwards|||n
+sv_pos_u2b_midway|||n
+sv_pos_u2b||5.006000|
+sv_pvbyten_force||5.006000|
+sv_pvbyten||5.006000|
+sv_pvbyte||5.006000|
+sv_pvn_force_flags|5.007002||p
+sv_pvn_force|||
+sv_pvn_nomg|5.007003||p
+sv_pvn|||
+sv_pvutf8n_force||5.006000|
+sv_pvutf8n||5.006000|
+sv_pvutf8||5.006000|
+sv_pv||5.006000|
+sv_recode_to_utf8||5.007003|
+sv_reftype|||
+sv_release_COW|||
+sv_replace|||
+sv_report_used|||
+sv_reset|||
+sv_rvweaken||5.006000|
+sv_setiv_mg|5.004050||p
+sv_setiv|||
+sv_setnv_mg|5.006000||p
+sv_setnv|||
+sv_setpv_mg|5.004050||p
+sv_setpvf_mg_nocontext|||pvn
+sv_setpvf_mg|5.006000|5.004000|pv
+sv_setpvf_nocontext|||vn
+sv_setpvf||5.004000|v
+sv_setpviv_mg||5.008001|
+sv_setpviv||5.008001|
+sv_setpvn_mg|5.004050||p
+sv_setpvn|||
+sv_setpvs|5.009004||p
+sv_setpv|||
+sv_setref_iv|||
+sv_setref_nv|||
+sv_setref_pvn|||
+sv_setref_pv|||
+sv_setref_uv||5.007001|
+sv_setsv_cow|||
+sv_setsv_flags||5.007002|
+sv_setsv_mg|5.004050||p
+sv_setsv_nomg|5.007002||p
+sv_setsv|||
+sv_setuv_mg|5.004050||p
+sv_setuv|5.004000||p
+sv_tainted||5.004000|
+sv_taint||5.004000|
+sv_true||5.005000|
+sv_unglob|||
+sv_uni_display||5.007003|
+sv_unmagic|||
+sv_unref_flags||5.007001|
+sv_unref|||
+sv_untaint||5.004000|
+sv_upgrade|||
+sv_usepvn_flags||5.009004|
+sv_usepvn_mg|5.004050||p
+sv_usepvn|||
+sv_utf8_decode||5.006000|
+sv_utf8_downgrade||5.006000|
+sv_utf8_encode||5.006000|
+sv_utf8_upgrade_flags||5.007002|
+sv_utf8_upgrade||5.007001|
+sv_uv|5.005000||p
+sv_vcatpvf_mg|5.006000|5.004000|p
+sv_vcatpvfn||5.004000|
+sv_vcatpvf|5.006000|5.004000|p
+sv_vsetpvf_mg|5.006000|5.004000|p
+sv_vsetpvfn||5.004000|
+sv_vsetpvf|5.006000|5.004000|p
+sv_xmlpeek|||
+svtype|||
+swallow_bom|||
+swash_fetch||5.007002|
+swash_get|||
+swash_init||5.006000|
+sys_intern_clear|||
+sys_intern_dup|||
+sys_intern_init|||
+taint_env|||
+taint_proper|||
+tmps_grow||5.006000|
+toLOWER|||
+toUPPER|||
+to_byte_substr|||
+to_uni_fold||5.007003|
+to_uni_lower_lc||5.006000|
+to_uni_lower||5.007003|
+to_uni_title_lc||5.006000|
+to_uni_title||5.007003|
+to_uni_upper_lc||5.006000|
+to_uni_upper||5.007003|
+to_utf8_case||5.007003|
+to_utf8_fold||5.007003|
+to_utf8_lower||5.007003|
+to_utf8_substr|||
+to_utf8_title||5.007003|
+to_utf8_upper||5.007003|
+token_free|||
+token_getmad|||
+tokenize_use|||
+tokeq|||
+tokereport|||
+too_few_arguments|||
+too_many_arguments|||
+uiv_2buf|||n
+unlnk|||
+unpack_rec|||
+unpack_str||5.007003|
+unpackstring||5.008001|
+unshare_hek_or_pvn|||
+unshare_hek|||
+unsharepvn||5.004000|
+unwind_handler_stack|||
+update_debugger_info|||
+upg_version||5.009005|
+usage|||
+utf16_to_utf8_reversed||5.006001|
+utf16_to_utf8||5.006001|
+utf8_distance||5.006000|
+utf8_hop||5.006000|
+utf8_length||5.007001|
+utf8_mg_pos_cache_update|||
+utf8_to_bytes||5.006001|
+utf8_to_uvchr||5.007001|
+utf8_to_uvuni||5.007001|
+utf8n_to_uvchr|||
+utf8n_to_uvuni||5.007001|
+utilize|||
+uvchr_to_utf8_flags||5.007003|
+uvchr_to_utf8|||
+uvuni_to_utf8_flags||5.007003|
+uvuni_to_utf8||5.007001|
+validate_suid|||
+varname|||
+vcmp||5.009000|
+vcroak||5.006000|
+vdeb||5.007003|
+vdie_common|||
+vdie_croak_common|||
+vdie|||
+vform||5.006000|
+visit|||
+vivify_defelem|||
+vivify_ref|||
+vload_module|5.006000||p
+vmess||5.006000|
+vnewSVpvf|5.006000|5.004000|p
+vnormal||5.009002|
+vnumify||5.009000|
+vstringify||5.009000|
+vverify||5.009003|
+vwarner||5.006000|
+vwarn||5.006000|
+wait4pid|||
+warn_nocontext|||vn
+warner_nocontext|||vn
+warner|5.006000|5.004000|pv
+warn|||v
+watch|||
+whichsig|||
+write_no_mem|||
+write_to_stderr|||
+xmldump_all|||
+xmldump_attr|||
+xmldump_eval|||
+xmldump_form|||
+xmldump_indent|||v
+xmldump_packsubs|||
+xmldump_sub|||
+xmldump_vindent|||
+yyerror|||
+yylex|||
+yyparse|||
+yywarn|||
+);
+
+if (exists $opt{'list-unsupported'}) {
+ my $f;
+ for $f (sort { lc $a cmp lc $b } keys %API) {
+ next unless $API{$f}{todo};
+ print "$f ", '.'x(40-length($f)), " ", format_version($API{$f}{todo}), "\n";
+ }
+ exit 0;
+}
+
+# Scan for possible replacement candidates
+
+my(%replace, %need, %hints, %warnings, %depends);
+my $replace = 0;
+my($hint, $define, $function);
+
+sub find_api
+{
+ my $code = shift;
+ $code =~ s{
+ / (?: \*[^*]*\*+(?:[^$ccs][^*]*\*+)* / | /[^\r\n]*)
+ | "[^"\\]*(?:\\.[^"\\]*)*"
+ | '[^'\\]*(?:\\.[^'\\]*)*' }{}egsx;
+ grep { exists $API{$_} } $code =~ /(\w+)/mg;
+}
+
+while (<DATA>) {
+ if ($hint) {
+ my $h = $hint->[0] eq 'Hint' ? \%hints : \%warnings;
+ if (m{^\s*\*\s(.*?)\s*$}) {
+ for (@{$hint->[1]}) {
+ $h->{$_} ||= ''; # suppress warning with older perls
+ $h->{$_} .= "$1\n";
+ }
+ }
+ else { undef $hint }
+ }
+
+ $hint = [$1, [split /,?\s+/, $2]]
+ if m{^\s*$rccs\s+(Hint|Warning):\s+(\w+(?:,?\s+\w+)*)\s*$};
+
+ if ($define) {
+ if ($define->[1] =~ /\\$/) {
+ $define->[1] .= $_;
+ }
+ else {
+ if (exists $API{$define->[0]} && $define->[1] !~ /^DPPP_\(/) {
+ my @n = find_api($define->[1]);
+ push @{$depends{$define->[0]}}, @n if @n
+ }
+ undef $define;
+ }
+ }
+
+ $define = [$1, $2] if m{^\s*#\s*define\s+(\w+)(?:\([^)]*\))?\s+(.*)};
+
+ if ($function) {
+ if (/^}/) {
+ if (exists $API{$function->[0]}) {
+ my @n = find_api($function->[1]);
+ push @{$depends{$function->[0]}}, @n if @n
+ }
+ undef $define;
+ }
+ else {
+ $function->[1] .= $_;
+ }
+ }
+
+ $function = [$1, ''] if m{^DPPP_\(my_(\w+)\)};
+
+ $replace = $1 if m{^\s*$rccs\s+Replace:\s+(\d+)\s+$rcce\s*$};
+ $replace{$2} = $1 if $replace and m{^\s*#\s*define\s+(\w+)(?:\([^)]*\))?\s+(\w+)};
+ $replace{$2} = $1 if m{^\s*#\s*define\s+(\w+)(?:\([^)]*\))?\s+(\w+).*$rccs\s+Replace\s+$rcce};
+ $replace{$1} = $2 if m{^\s*$rccs\s+Replace (\w+) with (\w+)\s+$rcce\s*$};
+
+ if (m{^\s*$rccs\s+(\w+)\s+depends\s+on\s+(\w+(\s*,\s*\w+)*)\s+$rcce\s*$}) {
+ push @{$depends{$1}}, map { s/\s+//g; $_ } split /,/, $2;
+ }
+
+ $need{$1} = 1 if m{^#if\s+defined\(NEED_(\w+)(?:_GLOBAL)?\)};
+}
+
+for (values %depends) {
+ my %s;
+ $_ = [sort grep !$s{$_}++, @$_];
+}
+
+if (exists $opt{'api-info'}) {
+ my $f;
+ my $count = 0;
+ my $match = $opt{'api-info'} =~ m!^/(.*)/$! ? $1 : "^\Q$opt{'api-info'}\E\$";
+ for $f (sort { lc $a cmp lc $b } keys %API) {
+ next unless $f =~ /$match/;
+ print "\n=== $f ===\n\n";
+ my $info = 0;
+ if ($API{$f}{base} || $API{$f}{todo}) {
+ my $base = format_version($API{$f}{base} || $API{$f}{todo});
+ print "Supported at least starting from perl-$base.\n";
+ $info++;
+ }
+ if ($API{$f}{provided}) {
+ my $todo = $API{$f}{todo} ? format_version($API{$f}{todo}) : "5.003";
+ print "Support by $ppport provided back to perl-$todo.\n";
+ print "Support needs to be explicitly requested by NEED_$f.\n" if exists $need{$f};
+ print "Depends on: ", join(', ', @{$depends{$f}}), ".\n" if exists $depends{$f};
+ print "\n$hints{$f}" if exists $hints{$f};
+ print "\nWARNING:\n$warnings{$f}" if exists $warnings{$f};
+ $info++;
+ }
+ print "No portability information available.\n" unless $info;
+ $count++;
+ }
+ $count or print "Found no API matching '$opt{'api-info'}'.";
+ print "\n";
+ exit 0;
+}
+
+if (exists $opt{'list-provided'}) {
+ my $f;
+ for $f (sort { lc $a cmp lc $b } keys %API) {
+ next unless $API{$f}{provided};
+ my @flags;
+ push @flags, 'explicit' if exists $need{$f};
+ push @flags, 'depend' if exists $depends{$f};
+ push @flags, 'hint' if exists $hints{$f};
+ push @flags, 'warning' if exists $warnings{$f};
+ my $flags = @flags ? ' ['.join(', ', @flags).']' : '';
+ print "$f$flags\n";
+ }
+ exit 0;
+}
+
+my @files;
+my @srcext = qw( .xs .c .h .cc .cpp -c.inc -xs.inc );
+my $srcext = join '|', map { quotemeta $_ } @srcext;
+
+if (@ARGV) {
+ my %seen;
+ for (@ARGV) {
+ if (-e) {
+ if (-f) {
+ push @files, $_ unless $seen{$_}++;
+ }
+ else { warn "'$_' is not a file.\n" }
+ }
+ else {
+ my @new = grep { -f } glob $_
+ or warn "'$_' does not exist.\n";
+ push @files, grep { !$seen{$_}++ } @new;
+ }
+ }
+}
+else {
+ eval {
+ require File::Find;
+ File::Find::find(sub {
+ $File::Find::name =~ /($srcext)$/i
+ and push @files, $File::Find::name;
+ }, '.');
+ };
+ if ($@) {
+ @files = map { glob "*$_" } @srcext;
+ }
+}
+
+if (!@ARGV || $opt{filter}) {
+ my(@in, @out);
+ my %xsc = map { /(.*)\.xs$/ ? ("$1.c" => 1, "$1.cc" => 1) : () } @files;
+ for (@files) {
+ my $out = exists $xsc{$_} || /\b\Q$ppport\E$/i || !/($srcext)$/i;
+ push @{ $out ? \@out : \@in }, $_;
+ }
+ if (@ARGV && @out) {
+ warning("Skipping the following files (use --nofilter to avoid this):\n| ", join "\n| ", @out);
+ }
+ @files = @in;
+}
+
+die "No input files given!\n" unless @files;
+
+my(%files, %global, %revreplace);
+%revreplace = reverse %replace;
+my $filename;
+my $patch_opened = 0;
+
+for $filename (@files) {
+ unless (open IN, "<$filename") {
+ warn "Unable to read from $filename: $!\n";
+ next;
+ }
+
+ info("Scanning $filename ...");
+
+ my $c = do { local $/; <IN> };
+ close IN;
+
+ my %file = (orig => $c, changes => 0);
+
+ # Temporarily remove C/XS comments and strings from the code
+ my @ccom;
+
+ $c =~ s{
+ ( ^$HS*\#$HS*include\b[^\r\n]+\b(?:\Q$ppport\E|XSUB\.h)\b[^\r\n]*
+ | ^$HS*\#$HS*(?:define|elif|if(?:def)?)\b[^\r\n]* )
+ | ( ^$HS*\#[^\r\n]*
+ | "[^"\\]*(?:\\.[^"\\]*)*"
+ | '[^'\\]*(?:\\.[^'\\]*)*'
+ | / (?: \*[^*]*\*+(?:[^$ccs][^*]*\*+)* / | /[^\r\n]* ) )
+ }{ defined $2 and push @ccom, $2;
+ defined $1 ? $1 : "$ccs$#ccom$cce" }mgsex;
+
+ $file{ccom} = \@ccom;
+ $file{code} = $c;
+ $file{has_inc_ppport} = $c =~ /^$HS*#$HS*include[^\r\n]+\b\Q$ppport\E\b/m;
+
+ my $func;
+
+ for $func (keys %API) {
+ my $match = $func;
+ $match .= "|$revreplace{$func}" if exists $revreplace{$func};
+ if ($c =~ /\b(?:Perl_)?($match)\b/) {
+ $file{uses_replace}{$1}++ if exists $revreplace{$func} && $1 eq $revreplace{$func};
+ $file{uses_Perl}{$func}++ if $c =~ /\bPerl_$func\b/;
+ if (exists $API{$func}{provided}) {
+ $file{uses_provided}{$func}++;
+ if (!exists $API{$func}{base} || $API{$func}{base} > $opt{'compat-version'}) {
+ $file{uses}{$func}++;
+ my @deps = rec_depend($func);
+ if (@deps) {
+ $file{uses_deps}{$func} = \@deps;
+ for (@deps) {
+ $file{uses}{$_} = 0 unless exists $file{uses}{$_};
+ }
+ }
+ for ($func, @deps) {
+ $file{needs}{$_} = 'static' if exists $need{$_};
+ }
+ }
+ }
+ if (exists $API{$func}{todo} && $API{$func}{todo} > $opt{'compat-version'}) {
+ if ($c =~ /\b$func\b/) {
+ $file{uses_todo}{$func}++;
+ }
+ }
+ }
+ }
+
+ while ($c =~ /^$HS*#$HS*define$HS+(NEED_(\w+?)(_GLOBAL)?)\b/mg) {
+ if (exists $need{$2}) {
+ $file{defined $3 ? 'needed_global' : 'needed_static'}{$2}++;
+ }
+ else { warning("Possibly wrong #define $1 in $filename") }
+ }
+
+ for (qw(uses needs uses_todo needed_global needed_static)) {
+ for $func (keys %{$file{$_}}) {
+ push @{$global{$_}{$func}}, $filename;
+ }
+ }
+
+ $files{$filename} = \%file;
+}
+
+# Globally resolve NEED_'s
+my $need;
+for $need (keys %{$global{needs}}) {
+ if (@{$global{needs}{$need}} > 1) {
+ my @targets = @{$global{needs}{$need}};
+ my @t = grep $files{$_}{needed_global}{$need}, @targets;
+ @targets = @t if @t;
+ @t = grep /\.xs$/i, @targets;
+ @targets = @t if @t;
+ my $target = shift @targets;
+ $files{$target}{needs}{$need} = 'global';
+ for (@{$global{needs}{$need}}) {
+ $files{$_}{needs}{$need} = 'extern' if $_ ne $target;
+ }
+ }
+}
+
+for $filename (@files) {
+ exists $files{$filename} or next;
+
+ info("=== Analyzing $filename ===");
+
+ my %file = %{$files{$filename}};
+ my $func;
+ my $c = $file{code};
+ my $warnings = 0;
+
+ for $func (sort keys %{$file{uses_Perl}}) {
+ if ($API{$func}{varargs}) {
+ unless ($API{$func}{nothxarg}) {
+ my $changes = ($c =~ s{\b(Perl_$func\s*\(\s*)(?!aTHX_?)(\)|[^\s)]*\))}
+ { $1 . ($2 eq ')' ? 'aTHX' : 'aTHX_ ') . $2 }ge);
+ if ($changes) {
+ warning("Doesn't pass interpreter argument aTHX to Perl_$func");
+ $file{changes} += $changes;
+ }
+ }
+ }
+ else {
+ warning("Uses Perl_$func instead of $func");
+ $file{changes} += ($c =~ s{\bPerl_$func(\s*)\((\s*aTHX_?)?\s*}
+ {$func$1(}g);
+ }
+ }
+
+ for $func (sort keys %{$file{uses_replace}}) {
+ warning("Uses $func instead of $replace{$func}");
+ $file{changes} += ($c =~ s/\b$func\b/$replace{$func}/g);
+ }
+
+ for $func (sort keys %{$file{uses_provided}}) {
+ if ($file{uses}{$func}) {
+ if (exists $file{uses_deps}{$func}) {
+ diag("Uses $func, which depends on ", join(', ', @{$file{uses_deps}{$func}}));
+ }
+ else {
+ diag("Uses $func");
+ }
+ }
+ $warnings += hint($func);
+ }
+
+ unless ($opt{quiet}) {
+ for $func (sort keys %{$file{uses_todo}}) {
+ print "*** WARNING: Uses $func, which may not be portable below perl ",
+ format_version($API{$func}{todo}), ", even with '$ppport'\n";
+ $warnings++;
+ }
+ }
+
+ for $func (sort keys %{$file{needed_static}}) {
+ my $message = '';
+ if (not exists $file{uses}{$func}) {
+ $message = "No need to define NEED_$func if $func is never used";
+ }
+ elsif (exists $file{needs}{$func} && $file{needs}{$func} ne 'static') {
+ $message = "No need to define NEED_$func when already needed globally";
+ }
+ if ($message) {
+ diag($message);
+ $file{changes} += ($c =~ s/^$HS*#$HS*define$HS+NEED_$func\b.*$LF//mg);
+ }
+ }
+
+ for $func (sort keys %{$file{needed_global}}) {
+ my $message = '';
+ if (not exists $global{uses}{$func}) {
+ $message = "No need to define NEED_${func}_GLOBAL if $func is never used";
+ }
+ elsif (exists $file{needs}{$func}) {
+ if ($file{needs}{$func} eq 'extern') {
+ $message = "No need to define NEED_${func}_GLOBAL when already needed globally";
+ }
+ elsif ($file{needs}{$func} eq 'static') {
+ $message = "No need to define NEED_${func}_GLOBAL when only used in this file";
+ }
+ }
+ if ($message) {
+ diag($message);
+ $file{changes} += ($c =~ s/^$HS*#$HS*define$HS+NEED_${func}_GLOBAL\b.*$LF//mg);
+ }
+ }
+
+ $file{needs_inc_ppport} = keys %{$file{uses}};
+
+ if ($file{needs_inc_ppport}) {
+ my $pp = '';
+
+ for $func (sort keys %{$file{needs}}) {
+ my $type = $file{needs}{$func};
+ next if $type eq 'extern';
+ my $suffix = $type eq 'global' ? '_GLOBAL' : '';
+ unless (exists $file{"needed_$type"}{$func}) {
+ if ($type eq 'global') {
+ diag("Files [@{$global{needs}{$func}}] need $func, adding global request");
+ }
+ else {
+ diag("File needs $func, adding static request");
+ }
+ $pp .= "#define NEED_$func$suffix\n";
+ }
+ }
+
+ if ($pp && ($c =~ s/^(?=$HS*#$HS*define$HS+NEED_\w+)/$pp/m)) {
+ $pp = '';
+ $file{changes}++;
+ }
+
+ unless ($file{has_inc_ppport}) {
+ diag("Needs to include '$ppport'");
+ $pp .= qq(#include "$ppport"\n)
+ }
+
+ if ($pp) {
+ $file{changes} += ($c =~ s/^($HS*#$HS*define$HS+NEED_\w+.*?)^/$1$pp/ms)
+ || ($c =~ s/^(?=$HS*#$HS*include.*\Q$ppport\E)/$pp/m)
+ || ($c =~ s/^($HS*#$HS*include.*XSUB.*\s*?)^/$1$pp/m)
+ || ($c =~ s/^/$pp/);
+ }
+ }
+ else {
+ if ($file{has_inc_ppport}) {
+ diag("No need to include '$ppport'");
+ $file{changes} += ($c =~ s/^$HS*?#$HS*include.*\Q$ppport\E.*?$LF//m);
+ }
+ }
+
+ # put back in our C comments
+ my $ix;
+ my $cppc = 0;
+ my @ccom = @{$file{ccom}};
+ for $ix (0 .. $#ccom) {
+ if (!$opt{cplusplus} && $ccom[$ix] =~ s!^//!!) {
+ $cppc++;
+ $file{changes} += $c =~ s/$rccs$ix$rcce/$ccs$ccom[$ix] $cce/;
+ }
+ else {
+ $c =~ s/$rccs$ix$rcce/$ccom[$ix]/;
+ }
+ }
+
+ if ($cppc) {
+ my $s = $cppc != 1 ? 's' : '';
+ warning("Uses $cppc C++ style comment$s, which is not portable");
+ }
+
+ my $s = $warnings != 1 ? 's' : '';
+ my $warn = $warnings ? " ($warnings warning$s)" : '';
+ info("Analysis completed$warn");
+
+ if ($file{changes}) {
+ if (exists $opt{copy}) {
+ my $newfile = "$filename$opt{copy}";
+ if (-e $newfile) {
+ error("'$newfile' already exists, refusing to write copy of '$filename'");
+ }
+ else {
+ local *F;
+ if (open F, ">$newfile") {
+ info("Writing copy of '$filename' with changes to '$newfile'");
+ print F $c;
+ close F;
+ }
+ else {
+ error("Cannot open '$newfile' for writing: $!");
+ }
+ }
+ }
+ elsif (exists $opt{patch} || $opt{changes}) {
+ if (exists $opt{patch}) {
+ unless ($patch_opened) {
+ if (open PATCH, ">$opt{patch}") {
+ $patch_opened = 1;
+ }
+ else {
+ error("Cannot open '$opt{patch}' for writing: $!");
+ delete $opt{patch};
+ $opt{changes} = 1;
+ goto fallback;
+ }
+ }
+ mydiff(\*PATCH, $filename, $c);
+ }
+ else {
+fallback:
+ info("Suggested changes:");
+ mydiff(\*STDOUT, $filename, $c);
+ }
+ }
+ else {
+ my $s = $file{changes} == 1 ? '' : 's';
+ info("$file{changes} potentially required change$s detected");
+ }
+ }
+ else {
+ info("Looks good");
+ }
+}
+
+close PATCH if $patch_opened;
+
+exit 0;
+
+
+sub try_use { eval "use @_;"; return $@ eq '' }
+
+sub mydiff
+{
+ local *F = shift;
+ my($file, $str) = @_;
+ my $diff;
+
+ if (exists $opt{diff}) {
+ $diff = run_diff($opt{diff}, $file, $str);
+ }
+
+ if (!defined $diff and try_use('Text::Diff')) {
+ $diff = Text::Diff::diff($file, \$str, { STYLE => 'Unified' });
+ $diff = <<HEADER . $diff;
+--- $file
++++ $file.patched
+HEADER
+ }
+
+ if (!defined $diff) {
+ $diff = run_diff('diff -u', $file, $str);
+ }
+
+ if (!defined $diff) {
+ $diff = run_diff('diff', $file, $str);
+ }
+
+ if (!defined $diff) {
+ error("Cannot generate a diff. Please install Text::Diff or use --copy.");
+ return;
+ }
+
+ print F $diff;
+}
+
+sub run_diff
+{
+ my($prog, $file, $str) = @_;
+ my $tmp = 'dppptemp';
+ my $suf = 'aaa';
+ my $diff = '';
+ local *F;
+
+ while (-e "$tmp.$suf") { $suf++ }
+ $tmp = "$tmp.$suf";
+
+ if (open F, ">$tmp") {
+ print F $str;
+ close F;
+
+ if (open F, "$prog $file $tmp |") {
+ while (<F>) {
+ s/\Q$tmp\E/$file.patched/;
+ $diff .= $_;
+ }
+ close F;
+ unlink $tmp;
+ return $diff;
+ }
+
+ unlink $tmp;
+ }
+ else {
+ error("Cannot open '$tmp' for writing: $!");
+ }
+
+ return undef;
+}
+
+sub rec_depend
+{
+ my($func, $seen) = @_;
+ return () unless exists $depends{$func};
+ $seen = {%{$seen||{}}};
+ return () if $seen->{$func}++;
+ my %s;
+ grep !$s{$_}++, map { ($_, rec_depend($_, $seen)) } @{$depends{$func}};
+}
+
+sub parse_version
+{
+ my $ver = shift;
+
+ if ($ver =~ /^(\d+)\.(\d+)\.(\d+)$/) {
+ return ($1, $2, $3);
+ }
+ elsif ($ver !~ /^\d+\.[\d_]+$/) {
+ die "cannot parse version '$ver'\n";
+ }
+
+ $ver =~ s/_//g;
+ $ver =~ s/$/000000/;
+
+ my($r,$v,$s) = $ver =~ /(\d+)\.(\d{3})(\d{3})/;
+
+ $v = int $v;
+ $s = int $s;
+
+ if ($r < 5 || ($r == 5 && $v < 6)) {
+ if ($s % 10) {
+ die "cannot parse version '$ver'\n";
+ }
+ }
+
+ return ($r, $v, $s);
+}
+
+sub format_version
+{
+ my $ver = shift;
+
+ $ver =~ s/$/000000/;
+ my($r,$v,$s) = $ver =~ /(\d+)\.(\d{3})(\d{3})/;
+
+ $v = int $v;
+ $s = int $s;
+
+ if ($r < 5 || ($r == 5 && $v < 6)) {
+ if ($s % 10) {
+ die "invalid version '$ver'\n";
+ }
+ $s /= 10;
+
+ $ver = sprintf "%d.%03d", $r, $v;
+ $s > 0 and $ver .= sprintf "_%02d", $s;
+
+ return $ver;
+ }
+
+ return sprintf "%d.%d.%d", $r, $v, $s;
+}
+
+sub info
+{
+ $opt{quiet} and return;
+ print @_, "\n";
+}
+
+sub diag
+{
+ $opt{quiet} and return;
+ $opt{diag} and print @_, "\n";
+}
+
+sub warning
+{
+ $opt{quiet} and return;
+ print "*** ", @_, "\n";
+}
+
+sub error
+{
+ print "*** ERROR: ", @_, "\n";
+}
+
+my %given_hints;
+my %given_warnings;
+sub hint
+{
+ $opt{quiet} and return;
+ my $func = shift;
+ my $rv = 0;
+ if (exists $warnings{$func} && !$given_warnings{$func}++) {
+ my $warn = $warnings{$func};
+ $warn =~ s!^!*** !mg;
+ print "*** WARNING: $func\n", $warn;
+ $rv++;
+ }
+ if ($opt{hints} && exists $hints{$func} && !$given_hints{$func}++) {
+ my $hint = $hints{$func};
+ $hint =~ s/^/ /mg;
+ print " --- hint for $func ---\n", $hint;
+ }
+ $rv;
+}
+
+sub usage
+{
+ my($usage) = do { local(@ARGV,$/)=($0); <> } =~ /^=head\d$HS+SYNOPSIS\s*^(.*?)\s*^=/ms;
+ my %M = ( 'I' => '*' );
+ $usage =~ s/^\s*perl\s+\S+/$^X $0/;
+ $usage =~ s/([A-Z])<([^>]+)>/$M{$1}$2$M{$1}/g;
+
+ print <<ENDUSAGE;
+
+Usage: $usage
+
+See perldoc $0 for details.
+
+ENDUSAGE
+
+ exit 2;
+}
+
+sub strip
+{
+ my $self = do { local(@ARGV,$/)=($0); <> };
+ my($copy) = $self =~ /^=head\d\s+COPYRIGHT\s*^(.*?)^=\w+/ms;
+ $copy =~ s/^(?=\S+)/ /gms;
+ $self =~ s/^$HS+Do NOT edit.*?(?=^-)/$copy/ms;
+ $self =~ s/^SKIP.*(?=^__DATA__)/SKIP
+if (\@ARGV && \$ARGV[0] eq '--unstrip') {
+ eval { require Devel::PPPort };
+ \$@ and die "Cannot require Devel::PPPort, please install.\\n";
+ if (\$Devel::PPPort::VERSION < $VERSION) {
+ die "$0 was originally generated with Devel::PPPort $VERSION.\\n"
+ . "Your Devel::PPPort is only version \$Devel::PPPort::VERSION.\\n"
+ . "Please install a newer version, or --unstrip will not work.\\n";
+ }
+ Devel::PPPort::WriteFile(\$0);
+ exit 0;
+}
+print <<END;
+
+Sorry, but this is a stripped version of \$0.
+
+To be able to use its original script and doc functionality,
+please try to regenerate this file using:
+
+ \$^X \$0 --unstrip
+
+END
+/ms;
+ my($pl, $c) = $self =~ /(.*^__DATA__)(.*)/ms;
+ $c =~ s{
+ / (?: \*[^*]*\*+(?:[^$ccs][^*]*\*+)* / | /[^\r\n]*)
+ | ( "[^"\\]*(?:\\.[^"\\]*)*"
+ | '[^'\\]*(?:\\.[^'\\]*)*' )
+ | ($HS+) }{ defined $2 ? ' ' : ($1 || '') }gsex;
+ $c =~ s!\s+$!!mg;
+ $c =~ s!^$LF!!mg;
+ $c =~ s!^\s*#\s*!#!mg;
+ $c =~ s!^\s+!!mg;
+
+ open OUT, ">$0" or die "cannot strip $0: $!\n";
+ print OUT "$pl$c\n";
+
+ exit 0;
+}
+
+__DATA__
+*/
+
+#ifndef _P_P_PORTABILITY_H_
+#define _P_P_PORTABILITY_H_
+
+#ifndef DPPP_NAMESPACE
+# define DPPP_NAMESPACE DPPP_
+#endif
+
+#define DPPP_CAT2(x,y) CAT2(x,y)
+#define DPPP_(name) DPPP_CAT2(DPPP_NAMESPACE, name)
+
+#ifndef PERL_REVISION
+# if !defined(__PATCHLEVEL_H_INCLUDED__) && !(defined(PATCHLEVEL) && defined(SUBVERSION))
+# define PERL_PATCHLEVEL_H_IMPLICIT
+# include <patchlevel.h>
+# endif
+# if !(defined(PERL_VERSION) || (defined(SUBVERSION) && defined(PATCHLEVEL)))
+# include <could_not_find_Perl_patchlevel.h>
+# endif
+# ifndef PERL_REVISION
+# define PERL_REVISION (5)
+ /* Replace: 1 */
+# define PERL_VERSION PATCHLEVEL
+# define PERL_SUBVERSION SUBVERSION
+ /* Replace PERL_PATCHLEVEL with PERL_VERSION */
+ /* Replace: 0 */
+# endif
+#endif
+
+#define _dpppDEC2BCD(dec) ((((dec)/100)<<8)|((((dec)%100)/10)<<4)|((dec)%10))
+#define PERL_BCDVERSION ((_dpppDEC2BCD(PERL_REVISION)<<24)|(_dpppDEC2BCD(PERL_VERSION)<<12)|_dpppDEC2BCD(PERL_SUBVERSION))
+
+/* It is very unlikely that anyone will try to use this with Perl 6
+ (or greater), but who knows.
+ */
+#if PERL_REVISION != 5
+# error ppport.h only works with Perl version 5
+#endif /* PERL_REVISION != 5 */
+
+#ifdef I_LIMITS
+# include <limits.h>
+#endif
+
+#ifndef PERL_UCHAR_MIN
+# define PERL_UCHAR_MIN ((unsigned char)0)
+#endif
+
+#ifndef PERL_UCHAR_MAX
+# ifdef UCHAR_MAX
+# define PERL_UCHAR_MAX ((unsigned char)UCHAR_MAX)
+# else
+# ifdef MAXUCHAR
+# define PERL_UCHAR_MAX ((unsigned char)MAXUCHAR)
+# else
+# define PERL_UCHAR_MAX ((unsigned char)~(unsigned)0)
+# endif
+# endif
+#endif
+
+#ifndef PERL_USHORT_MIN
+# define PERL_USHORT_MIN ((unsigned short)0)
+#endif
+
+#ifndef PERL_USHORT_MAX
+# ifdef USHORT_MAX
+# define PERL_USHORT_MAX ((unsigned short)USHORT_MAX)
+# else
+# ifdef MAXUSHORT
+# define PERL_USHORT_MAX ((unsigned short)MAXUSHORT)
+# else
+# ifdef USHRT_MAX
+# define PERL_USHORT_MAX ((unsigned short)USHRT_MAX)
+# else
+# define PERL_USHORT_MAX ((unsigned short)~(unsigned)0)
+# endif
+# endif
+# endif
+#endif
+
+#ifndef PERL_SHORT_MAX
+# ifdef SHORT_MAX
+# define PERL_SHORT_MAX ((short)SHORT_MAX)
+# else
+# ifdef MAXSHORT /* Often used in <values.h> */
+# define PERL_SHORT_MAX ((short)MAXSHORT)
+# else
+# ifdef SHRT_MAX
+# define PERL_SHORT_MAX ((short)SHRT_MAX)
+# else
+# define PERL_SHORT_MAX ((short) (PERL_USHORT_MAX >> 1))
+# endif
+# endif
+# endif
+#endif
+
+#ifndef PERL_SHORT_MIN
+# ifdef SHORT_MIN
+# define PERL_SHORT_MIN ((short)SHORT_MIN)
+# else
+# ifdef MINSHORT
+# define PERL_SHORT_MIN ((short)MINSHORT)
+# else
+# ifdef SHRT_MIN
+# define PERL_SHORT_MIN ((short)SHRT_MIN)
+# else
+# define PERL_SHORT_MIN (-PERL_SHORT_MAX - ((3 & -1) == 3))
+# endif
+# endif
+# endif
+#endif
+
+#ifndef PERL_UINT_MAX
+# ifdef UINT_MAX
+# define PERL_UINT_MAX ((unsigned int)UINT_MAX)
+# else
+# ifdef MAXUINT
+# define PERL_UINT_MAX ((unsigned int)MAXUINT)
+# else
+# define PERL_UINT_MAX (~(unsigned int)0)
+# endif
+# endif
+#endif
+
+#ifndef PERL_UINT_MIN
+# define PERL_UINT_MIN ((unsigned int)0)
+#endif
+
+#ifndef PERL_INT_MAX
+# ifdef INT_MAX
+# define PERL_INT_MAX ((int)INT_MAX)
+# else
+# ifdef MAXINT /* Often used in <values.h> */
+# define PERL_INT_MAX ((int)MAXINT)
+# else
+# define PERL_INT_MAX ((int)(PERL_UINT_MAX >> 1))
+# endif
+# endif
+#endif
+
+#ifndef PERL_INT_MIN
+# ifdef INT_MIN
+# define PERL_INT_MIN ((int)INT_MIN)
+# else
+# ifdef MININT
+# define PERL_INT_MIN ((int)MININT)
+# else
+# define PERL_INT_MIN (-PERL_INT_MAX - ((3 & -1) == 3))
+# endif
+# endif
+#endif
+
+#ifndef PERL_ULONG_MAX
+# ifdef ULONG_MAX
+# define PERL_ULONG_MAX ((unsigned long)ULONG_MAX)
+# else
+# ifdef MAXULONG
+# define PERL_ULONG_MAX ((unsigned long)MAXULONG)
+# else
+# define PERL_ULONG_MAX (~(unsigned long)0)
+# endif
+# endif
+#endif
+
+#ifndef PERL_ULONG_MIN
+# define PERL_ULONG_MIN ((unsigned long)0L)
+#endif
+
+#ifndef PERL_LONG_MAX
+# ifdef LONG_MAX
+# define PERL_LONG_MAX ((long)LONG_MAX)
+# else
+# ifdef MAXLONG
+# define PERL_LONG_MAX ((long)MAXLONG)
+# else
+# define PERL_LONG_MAX ((long) (PERL_ULONG_MAX >> 1))
+# endif
+# endif
+#endif
+
+#ifndef PERL_LONG_MIN
+# ifdef LONG_MIN
+# define PERL_LONG_MIN ((long)LONG_MIN)
+# else
+# ifdef MINLONG
+# define PERL_LONG_MIN ((long)MINLONG)
+# else
+# define PERL_LONG_MIN (-PERL_LONG_MAX - ((3 & -1) == 3))
+# endif
+# endif
+#endif
+
+#if defined(HAS_QUAD) && (defined(convex) || defined(uts))
+# ifndef PERL_UQUAD_MAX
+# ifdef ULONGLONG_MAX
+# define PERL_UQUAD_MAX ((unsigned long long)ULONGLONG_MAX)
+# else
+# ifdef MAXULONGLONG
+# define PERL_UQUAD_MAX ((unsigned long long)MAXULONGLONG)
+# else
+# define PERL_UQUAD_MAX (~(unsigned long long)0)
+# endif
+# endif
+# endif
+
+# ifndef PERL_UQUAD_MIN
+# define PERL_UQUAD_MIN ((unsigned long long)0L)
+# endif
+
+# ifndef PERL_QUAD_MAX
+# ifdef LONGLONG_MAX
+# define PERL_QUAD_MAX ((long long)LONGLONG_MAX)
+# else
+# ifdef MAXLONGLONG
+# define PERL_QUAD_MAX ((long long)MAXLONGLONG)
+# else
+# define PERL_QUAD_MAX ((long long) (PERL_UQUAD_MAX >> 1))
+# endif
+# endif
+# endif
+
+# ifndef PERL_QUAD_MIN
+# ifdef LONGLONG_MIN
+# define PERL_QUAD_MIN ((long long)LONGLONG_MIN)
+# else
+# ifdef MINLONGLONG
+# define PERL_QUAD_MIN ((long long)MINLONGLONG)
+# else
+# define PERL_QUAD_MIN (-PERL_QUAD_MAX - ((3 & -1) == 3))
+# endif
+# endif
+# endif
+#endif
+
+/* This is based on code from 5.003 perl.h */
+#ifdef HAS_QUAD
+# ifdef cray
+#ifndef IVTYPE
+# define IVTYPE int
+#endif
+
+#ifndef IV_MIN
+# define IV_MIN PERL_INT_MIN
+#endif
+
+#ifndef IV_MAX
+# define IV_MAX PERL_INT_MAX
+#endif
+
+#ifndef UV_MIN
+# define UV_MIN PERL_UINT_MIN
+#endif
+
+#ifndef UV_MAX
+# define UV_MAX PERL_UINT_MAX
+#endif
+
+# ifdef INTSIZE
+#ifndef IVSIZE
+# define IVSIZE INTSIZE
+#endif
+
+# endif
+# else
+# if defined(convex) || defined(uts)
+#ifndef IVTYPE
+# define IVTYPE long long
+#endif
+
+#ifndef IV_MIN
+# define IV_MIN PERL_QUAD_MIN
+#endif
+
+#ifndef IV_MAX
+# define IV_MAX PERL_QUAD_MAX
+#endif
+
+#ifndef UV_MIN
+# define UV_MIN PERL_UQUAD_MIN
+#endif
+
+#ifndef UV_MAX
+# define UV_MAX PERL_UQUAD_MAX
+#endif
+
+# ifdef LONGLONGSIZE
+#ifndef IVSIZE
+# define IVSIZE LONGLONGSIZE
+#endif
+
+# endif
+# else
+#ifndef IVTYPE
+# define IVTYPE long
+#endif
+
+#ifndef IV_MIN
+# define IV_MIN PERL_LONG_MIN
+#endif
+
+#ifndef IV_MAX
+# define IV_MAX PERL_LONG_MAX
+#endif
+
+#ifndef UV_MIN
+# define UV_MIN PERL_ULONG_MIN
+#endif
+
+#ifndef UV_MAX
+# define UV_MAX PERL_ULONG_MAX
+#endif
+
+# ifdef LONGSIZE
+#ifndef IVSIZE
+# define IVSIZE LONGSIZE
+#endif
+
+# endif
+# endif
+# endif
+#ifndef IVSIZE
+# define IVSIZE 8
+#endif
+
+#ifndef PERL_QUAD_MIN
+# define PERL_QUAD_MIN IV_MIN
+#endif
+
+#ifndef PERL_QUAD_MAX
+# define PERL_QUAD_MAX IV_MAX
+#endif
+
+#ifndef PERL_UQUAD_MIN
+# define PERL_UQUAD_MIN UV_MIN
+#endif
+
+#ifndef PERL_UQUAD_MAX
+# define PERL_UQUAD_MAX UV_MAX
+#endif
+
+#else
+#ifndef IVTYPE
+# define IVTYPE long
+#endif
+
+#ifndef IV_MIN
+# define IV_MIN PERL_LONG_MIN
+#endif
+
+#ifndef IV_MAX
+# define IV_MAX PERL_LONG_MAX
+#endif
+
+#ifndef UV_MIN
+# define UV_MIN PERL_ULONG_MIN
+#endif
+
+#ifndef UV_MAX
+# define UV_MAX PERL_ULONG_MAX
+#endif
+
+#endif
+
+#ifndef IVSIZE
+# ifdef LONGSIZE
+# define IVSIZE LONGSIZE
+# else
+# define IVSIZE 4 /* A bold guess, but the best we can make. */
+# endif
+#endif
+#ifndef UVTYPE
+# define UVTYPE unsigned IVTYPE
+#endif
+
+#ifndef UVSIZE
+# define UVSIZE IVSIZE
+#endif
+#ifndef sv_setuv
+# define sv_setuv(sv, uv) \
+ STMT_START { \
+ UV TeMpUv = uv; \
+ if (TeMpUv <= IV_MAX) \
+ sv_setiv(sv, TeMpUv); \
+ else \
+ sv_setnv(sv, (double)TeMpUv); \
+ } STMT_END
+#endif
+#ifndef newSVuv
+# define newSVuv(uv) ((uv) <= IV_MAX ? newSViv((IV)uv) : newSVnv((NV)uv))
+#endif
+#ifndef sv_2uv
+# define sv_2uv(sv) ((PL_Sv = (sv)), (UV) (SvNOK(PL_Sv) ? SvNV(PL_Sv) : sv_2nv(PL_Sv)))
+#endif
+
+#ifndef SvUVX
+# define SvUVX(sv) ((UV)SvIVX(sv))
+#endif
+
+#ifndef SvUVXx
+# define SvUVXx(sv) SvUVX(sv)
+#endif
+
+#ifndef SvUV
+# define SvUV(sv) (SvIOK(sv) ? SvUVX(sv) : sv_2uv(sv))
+#endif
+
+#ifndef SvUVx
+# define SvUVx(sv) ((PL_Sv = (sv)), SvUV(PL_Sv))
+#endif
+
+/* Hint: sv_uv
+ * Always use the SvUVx() macro instead of sv_uv().
+ */
+#ifndef sv_uv
+# define sv_uv(sv) SvUVx(sv)
+#endif
+
+#if !defined(SvUOK) && defined(SvIOK_UV)
+# define SvUOK(sv) SvIOK_UV(sv)
+#endif
+#ifndef XST_mUV
+# define XST_mUV(i,v) (ST(i) = sv_2mortal(newSVuv(v)) )
+#endif
+
+#ifndef XSRETURN_UV
+# define XSRETURN_UV(v) STMT_START { XST_mUV(0,v); XSRETURN(1); } STMT_END
+#endif
+#ifndef PUSHu
+# define PUSHu(u) STMT_START { sv_setuv(TARG, (UV)(u)); PUSHTARG; } STMT_END
+#endif
+
+#ifndef XPUSHu
+# define XPUSHu(u) STMT_START { sv_setuv(TARG, (UV)(u)); XPUSHTARG; } STMT_END
+#endif
+
+#ifdef HAS_MEMCMP
+#ifndef memNE
+# define memNE(s1,s2,l) (memcmp(s1,s2,l))
+#endif
+
+#ifndef memEQ
+# define memEQ(s1,s2,l) (!memcmp(s1,s2,l))
+#endif
+
+#else
+#ifndef memNE
+# define memNE(s1,s2,l) (bcmp(s1,s2,l))
+#endif
+
+#ifndef memEQ
+# define memEQ(s1,s2,l) (!bcmp(s1,s2,l))
+#endif
+
+#endif
+#ifndef MoveD
+# define MoveD(s,d,n,t) memmove((char*)(d),(char*)(s), (n) * sizeof(t))
+#endif
+
+#ifndef CopyD
+# define CopyD(s,d,n,t) memcpy((char*)(d),(char*)(s), (n) * sizeof(t))
+#endif
+
+#ifdef HAS_MEMSET
+#ifndef ZeroD
+# define ZeroD(d,n,t) memzero((char*)(d), (n) * sizeof(t))
+#endif
+
+#else
+#ifndef ZeroD
+# define ZeroD(d,n,t) ((void)memzero((char*)(d), (n) * sizeof(t)), d)
+#endif
+
+#endif
+#ifndef PoisonWith
+# define PoisonWith(d,n,t,b) (void)memset((char*)(d), (U8)(b), (n) * sizeof(t))
+#endif
+
+#ifndef PoisonNew
+# define PoisonNew(d,n,t) PoisonWith(d,n,t,0xAB)
+#endif
+
+#ifndef PoisonFree
+# define PoisonFree(d,n,t) PoisonWith(d,n,t,0xEF)
+#endif
+
+#ifndef Poison
+# define Poison(d,n,t) PoisonFree(d,n,t)
+#endif
+#ifndef Newx
+# define Newx(v,n,t) New(0,v,n,t)
+#endif
+
+#ifndef Newxc
+# define Newxc(v,n,t,c) Newc(0,v,n,t,c)
+#endif
+
+#ifndef Newxz
+# define Newxz(v,n,t) Newz(0,v,n,t)
+#endif
+
+#ifndef PERL_UNUSED_DECL
+# ifdef HASATTRIBUTE
+# if (defined(__GNUC__) && defined(__cplusplus)) || defined(__INTEL_COMPILER)
+# define PERL_UNUSED_DECL
+# else
+# define PERL_UNUSED_DECL __attribute__((unused))
+# endif
+# else
+# define PERL_UNUSED_DECL
+# endif
+#endif
+
+#ifndef PERL_UNUSED_ARG
+# if defined(lint) && defined(S_SPLINT_S) /* www.splint.org */
+# include <note.h>
+# define PERL_UNUSED_ARG(x) NOTE(ARGUNUSED(x))
+# else
+# define PERL_UNUSED_ARG(x) ((void)x)
+# endif
+#endif
+
+#ifndef PERL_UNUSED_VAR
+# define PERL_UNUSED_VAR(x) ((void)x)
+#endif
+
+#ifndef PERL_UNUSED_CONTEXT
+# ifdef USE_ITHREADS
+# define PERL_UNUSED_CONTEXT PERL_UNUSED_ARG(my_perl)
+# else
+# define PERL_UNUSED_CONTEXT
+# endif
+#endif
+#ifndef NOOP
+# define NOOP /*EMPTY*/(void)0
+#endif
+
+#ifndef dNOOP
+# define dNOOP extern int /*@unused@*/ Perl___notused PERL_UNUSED_DECL
+#endif
+
+#ifndef NVTYPE
+# if defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE)
+# define NVTYPE long double
+# else
+# define NVTYPE double
+# endif
+typedef NVTYPE NV;
+#endif
+
+#ifndef INT2PTR
+
+# if (IVSIZE == PTRSIZE) && (UVSIZE == PTRSIZE)
+# define PTRV UV
+# define INT2PTR(any,d) (any)(d)
+# else
+# if PTRSIZE == LONGSIZE
+# define PTRV unsigned long
+# else
+# define PTRV unsigned
+# endif
+# define INT2PTR(any,d) (any)(PTRV)(d)
+# endif
+
+# define NUM2PTR(any,d) (any)(PTRV)(d)
+# define PTR2IV(p) INT2PTR(IV,p)
+# define PTR2UV(p) INT2PTR(UV,p)
+# define PTR2NV(p) NUM2PTR(NV,p)
+
+# if PTRSIZE == LONGSIZE
+# define PTR2ul(p) (unsigned long)(p)
+# else
+# define PTR2ul(p) INT2PTR(unsigned long,p)
+# endif
+
+#endif /* !INT2PTR */
+
+#undef START_EXTERN_C
+#undef END_EXTERN_C
+#undef EXTERN_C
+#ifdef __cplusplus
+# define START_EXTERN_C extern "C" {
+# define END_EXTERN_C }
+# define EXTERN_C extern "C"
+#else
+# define START_EXTERN_C
+# define END_EXTERN_C
+# define EXTERN_C extern
+#endif
+
+#if defined(PERL_GCC_PEDANTIC)
+# ifndef PERL_GCC_BRACE_GROUPS_FORBIDDEN
+# define PERL_GCC_BRACE_GROUPS_FORBIDDEN
+# endif
+#endif
+
+#if defined(__GNUC__) && !defined(PERL_GCC_BRACE_GROUPS_FORBIDDEN) && !defined(__cplusplus)
+# ifndef PERL_USE_GCC_BRACE_GROUPS
+# define PERL_USE_GCC_BRACE_GROUPS
+# endif
+#endif
+
+#undef STMT_START
+#undef STMT_END
+#ifdef PERL_USE_GCC_BRACE_GROUPS
+# define STMT_START (void)( /* gcc supports ``({ STATEMENTS; })'' */
+# define STMT_END )
+#else
+# if defined(VOIDFLAGS) && (VOIDFLAGS) && (defined(sun) || defined(__sun__)) && !defined(__GNUC__)
+# define STMT_START if (1)
+# define STMT_END else (void)0
+# else
+# define STMT_START do
+# define STMT_END while (0)
+# endif
+#endif
+#ifndef boolSV
+# define boolSV(b) ((b) ? &PL_sv_yes : &PL_sv_no)
+#endif
+
+/* DEFSV appears first in 5.004_56 */
+#ifndef DEFSV
+# define DEFSV GvSV(PL_defgv)
+#endif
+
+#ifndef SAVE_DEFSV
+# define SAVE_DEFSV SAVESPTR(GvSV(PL_defgv))
+#endif
+
+/* Older perls (<=5.003) lack AvFILLp */
+#ifndef AvFILLp
+# define AvFILLp AvFILL
+#endif
+#ifndef ERRSV
+# define ERRSV get_sv("@",FALSE)
+#endif
+#ifndef newSVpvn
+# define newSVpvn(data,len) ((data) \
+ ? ((len) ? newSVpv((data), (len)) : newSVpv("", 0)) \
+ : newSV(0))
+#endif
+
+/* Hint: gv_stashpvn
+ * This function's backport doesn't support the length parameter, but
+ * rather ignores it. Portability can only be ensured if the length
+ * parameter is used for speed reasons, but the length can always be
+ * correctly computed from the string argument.
+ */
+#ifndef gv_stashpvn
+# define gv_stashpvn(str,len,create) gv_stashpv(str,create)
+#endif
+
+/* Replace: 1 */
+#ifndef get_cv
+# define get_cv perl_get_cv
+#endif
+
+#ifndef get_sv
+# define get_sv perl_get_sv
+#endif
+
+#ifndef get_av
+# define get_av perl_get_av
+#endif
+
+#ifndef get_hv
+# define get_hv perl_get_hv
+#endif
+
+/* Replace: 0 */
+#ifndef dUNDERBAR
+# define dUNDERBAR dNOOP
+#endif
+
+#ifndef UNDERBAR
+# define UNDERBAR DEFSV
+#endif
+#ifndef dAX
+# define dAX I32 ax = MARK - PL_stack_base + 1
+#endif
+
+#ifndef dITEMS
+# define dITEMS I32 items = SP - MARK
+#endif
+#ifndef dXSTARG
+# define dXSTARG SV * targ = sv_newmortal()
+#endif
+#ifndef dAXMARK
+# define dAXMARK I32 ax = POPMARK; \
+ register SV ** const mark = PL_stack_base + ax++
+#endif
+#ifndef XSprePUSH
+# define XSprePUSH (sp = PL_stack_base + ax - 1)
+#endif
+
+#if (PERL_BCDVERSION < 0x5005000)
+# undef XSRETURN
+# define XSRETURN(off) \
+ STMT_START { \
+ PL_stack_sp = PL_stack_base + ax + ((off) - 1); \
+ return; \
+ } STMT_END
+#endif
+#ifndef PERL_ABS
+# define PERL_ABS(x) ((x) < 0 ? -(x) : (x))
+#endif
+#ifndef dVAR
+# define dVAR dNOOP
+#endif
+#ifndef SVf
+# define SVf "_"
+#endif
+#ifndef UTF8_MAXBYTES
+# define UTF8_MAXBYTES UTF8_MAXLEN
+#endif
+#ifndef PERL_HASH
+# define PERL_HASH(hash,str,len) \
+ STMT_START { \
+ const char *s_PeRlHaSh = str; \
+ I32 i_PeRlHaSh = len; \
+ U32 hash_PeRlHaSh = 0; \
+ while (i_PeRlHaSh--) \
+ hash_PeRlHaSh = hash_PeRlHaSh * 33 + *s_PeRlHaSh++; \
+ (hash) = hash_PeRlHaSh; \
+ } STMT_END
+#endif
+
+#ifndef PERL_SIGNALS_UNSAFE_FLAG
+
+#define PERL_SIGNALS_UNSAFE_FLAG 0x0001
+
+#if (PERL_BCDVERSION < 0x5008000)
+# define D_PPP_PERL_SIGNALS_INIT PERL_SIGNALS_UNSAFE_FLAG
+#else
+# define D_PPP_PERL_SIGNALS_INIT 0
+#endif
+
+#if defined(NEED_PL_signals)
+static U32 DPPP_(my_PL_signals) = D_PPP_PERL_SIGNALS_INIT;
+#elif defined(NEED_PL_signals_GLOBAL)
+U32 DPPP_(my_PL_signals) = D_PPP_PERL_SIGNALS_INIT;
+#else
+extern U32 DPPP_(my_PL_signals);
+#endif
+#define PL_signals DPPP_(my_PL_signals)
+
+#endif
+
+/* Hint: PL_ppaddr
+ * Calling an op via PL_ppaddr requires passing a context argument
+ * for threaded builds. Since the context argument is different for
+ * 5.005 perls, you can use aTHXR (supplied by ppport.h), which will
+ * automatically be defined as the correct argument.
+ */
+
+#if (PERL_BCDVERSION <= 0x5005005)
+/* Replace: 1 */
+# define PL_ppaddr ppaddr
+# define PL_no_modify no_modify
+/* Replace: 0 */
+#endif
+
+#if (PERL_BCDVERSION <= 0x5004005)
+/* Replace: 1 */
+# define PL_DBsignal DBsignal
+# define PL_DBsingle DBsingle
+# define PL_DBsub DBsub
+# define PL_DBtrace DBtrace
+# define PL_Sv Sv
+# define PL_compiling compiling
+# define PL_copline copline
+# define PL_curcop curcop
+# define PL_curstash curstash
+# define PL_debstash debstash
+# define PL_defgv defgv
+# define PL_diehook diehook
+# define PL_dirty dirty
+# define PL_dowarn dowarn
+# define PL_errgv errgv
+# define PL_expect expect
+# define PL_hexdigit hexdigit
+# define PL_hints hints
+# define PL_laststatval laststatval
+# define PL_na na
+# define PL_perl_destruct_level perl_destruct_level
+# define PL_perldb perldb
+# define PL_rsfp_filters rsfp_filters
+# define PL_rsfp rsfp
+# define PL_stack_base stack_base
+# define PL_stack_sp stack_sp
+# define PL_statcache statcache
+# define PL_stdingv stdingv
+# define PL_sv_arenaroot sv_arenaroot
+# define PL_sv_no sv_no
+# define PL_sv_undef sv_undef
+# define PL_sv_yes sv_yes
+# define PL_tainted tainted
+# define PL_tainting tainting
+/* Replace: 0 */
+#endif
+
+/* Warning: PL_expect, PL_copline, PL_rsfp, PL_rsfp_filters
+ * Do not use this variable. It is internal to the perl parser
+ * and may change or even be removed in the future. Note that
+ * as of perl 5.9.5 you cannot assign to this variable anymore.
+ */
+
+/* TODO: cannot assign to these vars; is it worth fixing? */
+#if (PERL_BCDVERSION >= 0x5009005)
+# define PL_expect (PL_parser ? PL_parser->expect : 0)
+# define PL_copline (PL_parser ? PL_parser->copline : 0)
+# define PL_rsfp (PL_parser ? PL_parser->rsfp : (PerlIO *) 0)
+# define PL_rsfp_filters (PL_parser ? PL_parser->rsfp_filters : (AV *) 0)
+#endif
+#ifndef dTHR
+# define dTHR dNOOP
+#endif
+#ifndef dTHX
+# define dTHX dNOOP
+#endif
+
+#ifndef dTHXa
+# define dTHXa(x) dNOOP
+#endif
+#ifndef pTHX
+# define pTHX void
+#endif
+
+#ifndef pTHX_
+# define pTHX_
+#endif
+
+#ifndef aTHX
+# define aTHX
+#endif
+
+#ifndef aTHX_
+# define aTHX_
+#endif
+
+#if (PERL_BCDVERSION < 0x5006000)
+# ifdef USE_THREADS
+# define aTHXR thr
+# define aTHXR_ thr,
+# else
+# define aTHXR
+# define aTHXR_
+# endif
+# define dTHXR dTHR
+#else
+# define aTHXR aTHX
+# define aTHXR_ aTHX_
+# define dTHXR dTHX
+#endif
+#ifndef dTHXoa
+# define dTHXoa(x) dTHXa(x)
+#endif
+#ifndef PUSHmortal
+# define PUSHmortal PUSHs(sv_newmortal())
+#endif
+
+#ifndef mPUSHp
+# define mPUSHp(p,l) sv_setpvn_mg(PUSHmortal, (p), (l))
+#endif
+
+#ifndef mPUSHn
+# define mPUSHn(n) sv_setnv_mg(PUSHmortal, (NV)(n))
+#endif
+
+#ifndef mPUSHi
+# define mPUSHi(i) sv_setiv_mg(PUSHmortal, (IV)(i))
+#endif
+
+#ifndef mPUSHu
+# define mPUSHu(u) sv_setuv_mg(PUSHmortal, (UV)(u))
+#endif
+#ifndef XPUSHmortal
+# define XPUSHmortal XPUSHs(sv_newmortal())
+#endif
+
+#ifndef mXPUSHp
+# define mXPUSHp(p,l) STMT_START { EXTEND(sp,1); sv_setpvn_mg(PUSHmortal, (p), (l)); } STMT_END
+#endif
+
+#ifndef mXPUSHn
+# define mXPUSHn(n) STMT_START { EXTEND(sp,1); sv_setnv_mg(PUSHmortal, (NV)(n)); } STMT_END
+#endif
+
+#ifndef mXPUSHi
+# define mXPUSHi(i) STMT_START { EXTEND(sp,1); sv_setiv_mg(PUSHmortal, (IV)(i)); } STMT_END
+#endif
+
+#ifndef mXPUSHu
+# define mXPUSHu(u) STMT_START { EXTEND(sp,1); sv_setuv_mg(PUSHmortal, (UV)(u)); } STMT_END
+#endif
+
+/* Replace: 1 */
+#ifndef call_sv
+# define call_sv perl_call_sv
+#endif
+
+#ifndef call_pv
+# define call_pv perl_call_pv
+#endif
+
+#ifndef call_argv
+# define call_argv perl_call_argv
+#endif
+
+#ifndef call_method
+# define call_method perl_call_method
+#endif
+#ifndef eval_sv
+# define eval_sv perl_eval_sv
+#endif
+#ifndef PERL_LOADMOD_DENY
+# define PERL_LOADMOD_DENY 0x1
+#endif
+
+#ifndef PERL_LOADMOD_NOIMPORT
+# define PERL_LOADMOD_NOIMPORT 0x2
+#endif
+
+#ifndef PERL_LOADMOD_IMPORT_OPS
+# define PERL_LOADMOD_IMPORT_OPS 0x4
+#endif
+
+/* Replace: 0 */
+
+/* Replace perl_eval_pv with eval_pv */
+
+#ifndef eval_pv
+#if defined(NEED_eval_pv)
+static SV* DPPP_(my_eval_pv)(char *p, I32 croak_on_error);
+static
+#else
+extern SV* DPPP_(my_eval_pv)(char *p, I32 croak_on_error);
+#endif
+
+#ifdef eval_pv
+# undef eval_pv
+#endif
+#define eval_pv(a,b) DPPP_(my_eval_pv)(aTHX_ a,b)
+#define Perl_eval_pv DPPP_(my_eval_pv)
+
+#if defined(NEED_eval_pv) || defined(NEED_eval_pv_GLOBAL)
+
+SV*
+DPPP_(my_eval_pv)(char *p, I32 croak_on_error)
+{
+ dSP;
+ SV* sv = newSVpv(p, 0);
+
+ PUSHMARK(sp);
+ eval_sv(sv, G_SCALAR);
+ SvREFCNT_dec(sv);
+
+ SPAGAIN;
+ sv = POPs;
+ PUTBACK;
+
+ if (croak_on_error && SvTRUE(GvSV(errgv)))
+ croak(SvPVx(GvSV(errgv), na));
+
+ return sv;
+}
+
+#endif
+#endif
+
+#ifndef vload_module
+#if defined(NEED_vload_module)
+static void DPPP_(my_vload_module)(U32 flags, SV *name, SV *ver, va_list *args);
+static
+#else
+extern void DPPP_(my_vload_module)(U32 flags, SV *name, SV *ver, va_list *args);
+#endif
+
+#ifdef vload_module
+# undef vload_module
+#endif
+#define vload_module(a,b,c,d) DPPP_(my_vload_module)(aTHX_ a,b,c,d)
+#define Perl_vload_module DPPP_(my_vload_module)
+
+#if defined(NEED_vload_module) || defined(NEED_vload_module_GLOBAL)
+
+void
+DPPP_(my_vload_module)(U32 flags, SV *name, SV *ver, va_list *args)
+{
+ dTHR;
+ dVAR;
+ OP *veop, *imop;
+
+ OP * const modname = newSVOP(OP_CONST, 0, name);
+ /* 5.005 has a somewhat hacky force_normal that doesn't croak on
+ SvREADONLY() if PL_compling is true. Current perls take care in
+ ck_require() to correctly turn off SvREADONLY before calling
+ force_normal_flags(). This seems a better fix than fudging PL_compling
+ */
+ SvREADONLY_off(((SVOP*)modname)->op_sv);
+ modname->op_private |= OPpCONST_BARE;
+ if (ver) {
+ veop = newSVOP(OP_CONST, 0, ver);
+ }
+ else
+ veop = NULL;
+ if (flags & PERL_LOADMOD_NOIMPORT) {
+ imop = sawparens(newNULLLIST());
+ }
+ else if (flags & PERL_LOADMOD_IMPORT_OPS) {
+ imop = va_arg(*args, OP*);
+ }
+ else {
+ SV *sv;
+ imop = NULL;
+ sv = va_arg(*args, SV*);
+ while (sv) {
+ imop = append_elem(OP_LIST, imop, newSVOP(OP_CONST, 0, sv));
+ sv = va_arg(*args, SV*);
+ }
+ }
+ {
+ const line_t ocopline = PL_copline;
+ COP * const ocurcop = PL_curcop;
+ const int oexpect = PL_expect;
+
+#if (PERL_BCDVERSION >= 0x5004000)
+ utilize(!(flags & PERL_LOADMOD_DENY), start_subparse(FALSE, 0),
+ veop, modname, imop);
+#else
+ utilize(!(flags & PERL_LOADMOD_DENY), start_subparse(),
+ modname, imop);
+#endif
+ PL_expect = oexpect;
+ PL_copline = ocopline;
+ PL_curcop = ocurcop;
+ }
+}
+
+#endif
+#endif
+
+#ifndef load_module
+#if defined(NEED_load_module)
+static void DPPP_(my_load_module)(U32 flags, SV *name, SV *ver, ...);
+static
+#else
+extern void DPPP_(my_load_module)(U32 flags, SV *name, SV *ver, ...);
+#endif
+
+#ifdef load_module
+# undef load_module
+#endif
+#define load_module DPPP_(my_load_module)
+#define Perl_load_module DPPP_(my_load_module)
+
+#if defined(NEED_load_module) || defined(NEED_load_module_GLOBAL)
+
+void
+DPPP_(my_load_module)(U32 flags, SV *name, SV *ver, ...)
+{
+ va_list args;
+ va_start(args, ver);
+ vload_module(flags, name, ver, &args);
+ va_end(args);
+}
+
+#endif
+#endif
+#ifndef newRV_inc
+# define newRV_inc(sv) newRV(sv) /* Replace */
+#endif
+
+#ifndef newRV_noinc
+#if defined(NEED_newRV_noinc)
+static SV * DPPP_(my_newRV_noinc)(SV *sv);
+static
+#else
+extern SV * DPPP_(my_newRV_noinc)(SV *sv);
+#endif
+
+#ifdef newRV_noinc
+# undef newRV_noinc
+#endif
+#define newRV_noinc(a) DPPP_(my_newRV_noinc)(aTHX_ a)
+#define Perl_newRV_noinc DPPP_(my_newRV_noinc)
+
+#if defined(NEED_newRV_noinc) || defined(NEED_newRV_noinc_GLOBAL)
+SV *
+DPPP_(my_newRV_noinc)(SV *sv)
+{
+ SV *rv = (SV *)newRV(sv);
+ SvREFCNT_dec(sv);
+ return rv;
+}
+#endif
+#endif
+
+/* Hint: newCONSTSUB
+ * Returns a CV* as of perl-5.7.1. This return value is not supported
+ * by Devel::PPPort.
+ */
+
+/* newCONSTSUB from IO.xs is in the core starting with 5.004_63 */
+#if (PERL_BCDVERSION < 0x5004063) && (PERL_BCDVERSION != 0x5004005)
+#if defined(NEED_newCONSTSUB)
+static void DPPP_(my_newCONSTSUB)(HV *stash, const char *name, SV *sv);
+static
+#else
+extern void DPPP_(my_newCONSTSUB)(HV *stash, const char *name, SV *sv);
+#endif
+
+#ifdef newCONSTSUB
+# undef newCONSTSUB
+#endif
+#define newCONSTSUB(a,b,c) DPPP_(my_newCONSTSUB)(aTHX_ a,b,c)
+#define Perl_newCONSTSUB DPPP_(my_newCONSTSUB)
+
+#if defined(NEED_newCONSTSUB) || defined(NEED_newCONSTSUB_GLOBAL)
+
+void
+DPPP_(my_newCONSTSUB)(HV *stash, const char *name, SV *sv)
+{
+ U32 oldhints = PL_hints;
+ HV *old_cop_stash = PL_curcop->cop_stash;
+ HV *old_curstash = PL_curstash;
+ line_t oldline = PL_curcop->cop_line;
+ PL_curcop->cop_line = PL_copline;
+
+ PL_hints &= ~HINT_BLOCK_SCOPE;
+ if (stash)
+ PL_curstash = PL_curcop->cop_stash = stash;
+
+ newSUB(
+
+#if (PERL_BCDVERSION < 0x5003022)
+ start_subparse(),
+#elif (PERL_BCDVERSION == 0x5003022)
+ start_subparse(0),
+#else /* 5.003_23 onwards */
+ start_subparse(FALSE, 0),
+#endif
+
+ newSVOP(OP_CONST, 0, newSVpv((char *) name, 0)),
+ newSVOP(OP_CONST, 0, &PL_sv_no), /* SvPV(&PL_sv_no) == "" -- GMB */
+ newSTATEOP(0, Nullch, newSVOP(OP_CONST, 0, sv))
+ );
+
+ PL_hints = oldhints;
+ PL_curcop->cop_stash = old_cop_stash;
+ PL_curstash = old_curstash;
+ PL_curcop->cop_line = oldline;
+}
+#endif
+#endif
+
+/*
+ * Boilerplate macros for initializing and accessing interpreter-local
+ * data from C. All statics in extensions should be reworked to use
+ * this, if you want to make the extension thread-safe. See ext/re/re.xs
+ * for an example of the use of these macros.
+ *
+ * Code that uses these macros is responsible for the following:
+ * 1. #define MY_CXT_KEY to a unique string, e.g. "DynaLoader_guts"
+ * 2. Declare a typedef named my_cxt_t that is a structure that contains
+ * all the data that needs to be interpreter-local.
+ * 3. Use the START_MY_CXT macro after the declaration of my_cxt_t.
+ * 4. Use the MY_CXT_INIT macro such that it is called exactly once
+ * (typically put in the BOOT: section).
+ * 5. Use the members of the my_cxt_t structure everywhere as
+ * MY_CXT.member.
+ * 6. Use the dMY_CXT macro (a declaration) in all the functions that
+ * access MY_CXT.
+ */
+
+#if defined(MULTIPLICITY) || defined(PERL_OBJECT) || \
+ defined(PERL_CAPI) || defined(PERL_IMPLICIT_CONTEXT)
+
+#ifndef START_MY_CXT
+
+/* This must appear in all extensions that define a my_cxt_t structure,
+ * right after the definition (i.e. at file scope). The non-threads
+ * case below uses it to declare the data as static. */
+#define START_MY_CXT
+
+#if (PERL_BCDVERSION < 0x5004068)
+/* Fetches the SV that keeps the per-interpreter data. */
+#define dMY_CXT_SV \
+ SV *my_cxt_sv = get_sv(MY_CXT_KEY, FALSE)
+#else /* >= perl5.004_68 */
+#define dMY_CXT_SV \
+ SV *my_cxt_sv = *hv_fetch(PL_modglobal, MY_CXT_KEY, \
+ sizeof(MY_CXT_KEY)-1, TRUE)
+#endif /* < perl5.004_68 */
+
+/* This declaration should be used within all functions that use the
+ * interpreter-local data. */
+#define dMY_CXT \
+ dMY_CXT_SV; \
+ my_cxt_t *my_cxtp = INT2PTR(my_cxt_t*,SvUV(my_cxt_sv))
+
+/* Creates and zeroes the per-interpreter data.
+ * (We allocate my_cxtp in a Perl SV so that it will be released when
+ * the interpreter goes away.) */
+#define MY_CXT_INIT \
+ dMY_CXT_SV; \
+ /* newSV() allocates one more than needed */ \
+ my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1));\
+ Zero(my_cxtp, 1, my_cxt_t); \
+ sv_setuv(my_cxt_sv, PTR2UV(my_cxtp))
+
+/* This macro must be used to access members of the my_cxt_t structure.
+ * e.g. MYCXT.some_data */
+#define MY_CXT (*my_cxtp)
+
+/* Judicious use of these macros can reduce the number of times dMY_CXT
+ * is used. Use is similar to pTHX, aTHX etc. */
+#define pMY_CXT my_cxt_t *my_cxtp
+#define pMY_CXT_ pMY_CXT,
+#define _pMY_CXT ,pMY_CXT
+#define aMY_CXT my_cxtp
+#define aMY_CXT_ aMY_CXT,
+#define _aMY_CXT ,aMY_CXT
+
+#endif /* START_MY_CXT */
+
+#ifndef MY_CXT_CLONE
+/* Clones the per-interpreter data. */
+#define MY_CXT_CLONE \
+ dMY_CXT_SV; \
+ my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1));\
+ Copy(INT2PTR(my_cxt_t*, SvUV(my_cxt_sv)), my_cxtp, 1, my_cxt_t);\
+ sv_setuv(my_cxt_sv, PTR2UV(my_cxtp))
+#endif
+
+#else /* single interpreter */
+
+#ifndef START_MY_CXT
+
+#define START_MY_CXT static my_cxt_t my_cxt;
+#define dMY_CXT_SV dNOOP
+#define dMY_CXT dNOOP
+#define MY_CXT_INIT NOOP
+#define MY_CXT my_cxt
+
+#define pMY_CXT void
+#define pMY_CXT_
+#define _pMY_CXT
+#define aMY_CXT
+#define aMY_CXT_
+#define _aMY_CXT
+
+#endif /* START_MY_CXT */
+
+#ifndef MY_CXT_CLONE
+#define MY_CXT_CLONE NOOP
+#endif
+
+#endif
+
+#ifndef IVdf
+# if IVSIZE == LONGSIZE
+# define IVdf "ld"
+# define UVuf "lu"
+# define UVof "lo"
+# define UVxf "lx"
+# define UVXf "lX"
+# else
+# if IVSIZE == INTSIZE
+# define IVdf "d"
+# define UVuf "u"
+# define UVof "o"
+# define UVxf "x"
+# define UVXf "X"
+# endif
+# endif
+#endif
+
+#ifndef NVef
+# if defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE) && \
+ defined(PERL_PRIfldbl) /* Not very likely, but let's try anyway. */
+# define NVef PERL_PRIeldbl
+# define NVff PERL_PRIfldbl
+# define NVgf PERL_PRIgldbl
+# else
+# define NVef "e"
+# define NVff "f"
+# define NVgf "g"
+# endif
+#endif
+
+#ifndef SvREFCNT_inc
+# ifdef PERL_USE_GCC_BRACE_GROUPS
+# define SvREFCNT_inc(sv) \
+ ({ \
+ SV * const _sv = (SV*)(sv); \
+ if (_sv) \
+ (SvREFCNT(_sv))++; \
+ _sv; \
+ })
+# else
+# define SvREFCNT_inc(sv) \
+ ((PL_Sv=(SV*)(sv)) ? (++(SvREFCNT(PL_Sv)),PL_Sv) : NULL)
+# endif
+#endif
+
+#ifndef SvREFCNT_inc_simple
+# ifdef PERL_USE_GCC_BRACE_GROUPS
+# define SvREFCNT_inc_simple(sv) \
+ ({ \
+ if (sv) \
+ (SvREFCNT(sv))++; \
+ (SV *)(sv); \
+ })
+# else
+# define SvREFCNT_inc_simple(sv) \
+ ((sv) ? (SvREFCNT(sv)++,(SV*)(sv)) : NULL)
+# endif
+#endif
+
+#ifndef SvREFCNT_inc_NN
+# ifdef PERL_USE_GCC_BRACE_GROUPS
+# define SvREFCNT_inc_NN(sv) \
+ ({ \
+ SV * const _sv = (SV*)(sv); \
+ SvREFCNT(_sv)++; \
+ _sv; \
+ })
+# else
+# define SvREFCNT_inc_NN(sv) \
+ (PL_Sv=(SV*)(sv),++(SvREFCNT(PL_Sv)),PL_Sv)
+# endif
+#endif
+
+#ifndef SvREFCNT_inc_void
+# ifdef PERL_USE_GCC_BRACE_GROUPS
+# define SvREFCNT_inc_void(sv) \
+ ({ \
+ SV * const _sv = (SV*)(sv); \
+ if (_sv) \
+ (void)(SvREFCNT(_sv)++); \
+ })
+# else
+# define SvREFCNT_inc_void(sv) \
+ (void)((PL_Sv=(SV*)(sv)) ? ++(SvREFCNT(PL_Sv)) : 0)
+# endif
+#endif
+#ifndef SvREFCNT_inc_simple_void
+# define SvREFCNT_inc_simple_void(sv) STMT_START { if (sv) SvREFCNT(sv)++; } STMT_END
+#endif
+
+#ifndef SvREFCNT_inc_simple_NN
+# define SvREFCNT_inc_simple_NN(sv) (++SvREFCNT(sv), (SV*)(sv))
+#endif
+
+#ifndef SvREFCNT_inc_void_NN
+# define SvREFCNT_inc_void_NN(sv) (void)(++SvREFCNT((SV*)(sv)))
+#endif
+
+#ifndef SvREFCNT_inc_simple_void_NN
+# define SvREFCNT_inc_simple_void_NN(sv) (void)(++SvREFCNT((SV*)(sv)))
+#endif
+
+/* Backwards compatibility stuff... :-( */
+#if !defined(NEED_sv_2pv_flags) && defined(NEED_sv_2pv_nolen)
+# define NEED_sv_2pv_flags
+#endif
+#if !defined(NEED_sv_2pv_flags_GLOBAL) && defined(NEED_sv_2pv_nolen_GLOBAL)
+# define NEED_sv_2pv_flags_GLOBAL
+#endif
+
+/* Hint: sv_2pv_nolen
+ * Use the SvPV_nolen() or SvPV_nolen_const() macros instead of sv_2pv_nolen().
+ */
+#ifndef sv_2pv_nolen
+# define sv_2pv_nolen(sv) SvPV_nolen(sv)
+#endif
+
+#ifdef SvPVbyte
+
+/* Hint: SvPVbyte
+ * Does not work in perl-5.6.1, ppport.h implements a version
+ * borrowed from perl-5.7.3.
+ */
+
+#if (PERL_BCDVERSION < 0x5007000)
+
+#if defined(NEED_sv_2pvbyte)
+static char * DPPP_(my_sv_2pvbyte)(pTHX_ SV * sv, STRLEN * lp);
+static
+#else
+extern char * DPPP_(my_sv_2pvbyte)(pTHX_ SV * sv, STRLEN * lp);
+#endif
+
+#ifdef sv_2pvbyte
+# undef sv_2pvbyte
+#endif
+#define sv_2pvbyte(a,b) DPPP_(my_sv_2pvbyte)(aTHX_ a,b)
+#define Perl_sv_2pvbyte DPPP_(my_sv_2pvbyte)
+
+#if defined(NEED_sv_2pvbyte) || defined(NEED_sv_2pvbyte_GLOBAL)
+
+char *
+DPPP_(my_sv_2pvbyte)(pTHX_ SV *sv, STRLEN *lp)
+{
+ sv_utf8_downgrade(sv,0);
+ return SvPV(sv,*lp);
+}
+
+#endif
+
+/* Hint: sv_2pvbyte
+ * Use the SvPVbyte() macro instead of sv_2pvbyte().
+ */
+
+#undef SvPVbyte
+
+#define SvPVbyte(sv, lp) \
+ ((SvFLAGS(sv) & (SVf_POK|SVf_UTF8)) == (SVf_POK) \
+ ? ((lp = SvCUR(sv)), SvPVX(sv)) : sv_2pvbyte(sv, &lp))
+
+#endif
+
+#else
+
+# define SvPVbyte SvPV
+# define sv_2pvbyte sv_2pv
+
+#endif
+#ifndef sv_2pvbyte_nolen
+# define sv_2pvbyte_nolen(sv) sv_2pv_nolen(sv)
+#endif
+
+/* Hint: sv_pvn
+ * Always use the SvPV() macro instead of sv_pvn().
+ */
+
+/* Hint: sv_pvn_force
+ * Always use the SvPV_force() macro instead of sv_pvn_force().
+ */
+
+/* If these are undefined, they're not handled by the core anyway */
+#ifndef SV_IMMEDIATE_UNREF
+# define SV_IMMEDIATE_UNREF 0
+#endif
+
+#ifndef SV_GMAGIC
+# define SV_GMAGIC 0
+#endif
+
+#ifndef SV_COW_DROP_PV
+# define SV_COW_DROP_PV 0
+#endif
+
+#ifndef SV_UTF8_NO_ENCODING
+# define SV_UTF8_NO_ENCODING 0
+#endif
+
+#ifndef SV_NOSTEAL
+# define SV_NOSTEAL 0
+#endif
+
+#ifndef SV_CONST_RETURN
+# define SV_CONST_RETURN 0
+#endif
+
+#ifndef SV_MUTABLE_RETURN
+# define SV_MUTABLE_RETURN 0
+#endif
+
+#ifndef SV_SMAGIC
+# define SV_SMAGIC 0
+#endif
+
+#ifndef SV_HAS_TRAILING_NUL
+# define SV_HAS_TRAILING_NUL 0
+#endif
+
+#ifndef SV_COW_SHARED_HASH_KEYS
+# define SV_COW_SHARED_HASH_KEYS 0
+#endif
+
+#if (PERL_BCDVERSION < 0x5007002)
+
+#if defined(NEED_sv_2pv_flags)
+static char * DPPP_(my_sv_2pv_flags)(pTHX_ SV * sv, STRLEN * lp, I32 flags);
+static
+#else
+extern char * DPPP_(my_sv_2pv_flags)(pTHX_ SV * sv, STRLEN * lp, I32 flags);
+#endif
+
+#ifdef sv_2pv_flags
+# undef sv_2pv_flags
+#endif
+#define sv_2pv_flags(a,b,c) DPPP_(my_sv_2pv_flags)(aTHX_ a,b,c)
+#define Perl_sv_2pv_flags DPPP_(my_sv_2pv_flags)
+
+#if defined(NEED_sv_2pv_flags) || defined(NEED_sv_2pv_flags_GLOBAL)
+
+char *
+DPPP_(my_sv_2pv_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags)
+{
+ STRLEN n_a = (STRLEN) flags;
+ return sv_2pv(sv, lp ? lp : &n_a);
+}
+
+#endif
+
+#if defined(NEED_sv_pvn_force_flags)
+static char * DPPP_(my_sv_pvn_force_flags)(pTHX_ SV * sv, STRLEN * lp, I32 flags);
+static
+#else
+extern char * DPPP_(my_sv_pvn_force_flags)(pTHX_ SV * sv, STRLEN * lp, I32 flags);
+#endif
+
+#ifdef sv_pvn_force_flags
+# undef sv_pvn_force_flags
+#endif
+#define sv_pvn_force_flags(a,b,c) DPPP_(my_sv_pvn_force_flags)(aTHX_ a,b,c)
+#define Perl_sv_pvn_force_flags DPPP_(my_sv_pvn_force_flags)
+
+#if defined(NEED_sv_pvn_force_flags) || defined(NEED_sv_pvn_force_flags_GLOBAL)
+
+char *
+DPPP_(my_sv_pvn_force_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags)
+{
+ STRLEN n_a = (STRLEN) flags;
+ return sv_pvn_force(sv, lp ? lp : &n_a);
+}
+
+#endif
+
+#endif
+#ifndef SvPV_const
+# define SvPV_const(sv, lp) SvPV_flags_const(sv, lp, SV_GMAGIC)
+#endif
+
+#ifndef SvPV_mutable
+# define SvPV_mutable(sv, lp) SvPV_flags_mutable(sv, lp, SV_GMAGIC)
+#endif
+#ifndef SvPV_flags
+# define SvPV_flags(sv, lp, flags) \
+ ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \
+ ? ((lp = SvCUR(sv)), SvPVX(sv)) : sv_2pv_flags(sv, &lp, flags))
+#endif
+#ifndef SvPV_flags_const
+# define SvPV_flags_const(sv, lp, flags) \
+ ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \
+ ? ((lp = SvCUR(sv)), SvPVX_const(sv)) : \
+ (const char*) sv_2pv_flags(sv, &lp, flags|SV_CONST_RETURN))
+#endif
+#ifndef SvPV_flags_const_nolen
+# define SvPV_flags_const_nolen(sv, flags) \
+ ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \
+ ? SvPVX_const(sv) : \
+ (const char*) sv_2pv_flags(sv, 0, flags|SV_CONST_RETURN))
+#endif
+#ifndef SvPV_flags_mutable
+# define SvPV_flags_mutable(sv, lp, flags) \
+ ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \
+ ? ((lp = SvCUR(sv)), SvPVX_mutable(sv)) : \
+ sv_2pv_flags(sv, &lp, flags|SV_MUTABLE_RETURN))
+#endif
+#ifndef SvPV_force
+# define SvPV_force(sv, lp) SvPV_force_flags(sv, lp, SV_GMAGIC)
+#endif
+
+#ifndef SvPV_force_nolen
+# define SvPV_force_nolen(sv) SvPV_force_flags_nolen(sv, SV_GMAGIC)
+#endif
+
+#ifndef SvPV_force_mutable
+# define SvPV_force_mutable(sv, lp) SvPV_force_flags_mutable(sv, lp, SV_GMAGIC)
+#endif
+
+#ifndef SvPV_force_nomg
+# define SvPV_force_nomg(sv, lp) SvPV_force_flags(sv, lp, 0)
+#endif
+
+#ifndef SvPV_force_nomg_nolen
+# define SvPV_force_nomg_nolen(sv) SvPV_force_flags_nolen(sv, 0)
+#endif
+#ifndef SvPV_force_flags
+# define SvPV_force_flags(sv, lp, flags) \
+ ((SvFLAGS(sv) & (SVf_POK|SVf_THINKFIRST)) == SVf_POK \
+ ? ((lp = SvCUR(sv)), SvPVX(sv)) : sv_pvn_force_flags(sv, &lp, flags))
+#endif
+#ifndef SvPV_force_flags_nolen
+# define SvPV_force_flags_nolen(sv, flags) \
+ ((SvFLAGS(sv) & (SVf_POK|SVf_THINKFIRST)) == SVf_POK \
+ ? SvPVX(sv) : sv_pvn_force_flags(sv, 0, flags))
+#endif
+#ifndef SvPV_force_flags_mutable
+# define SvPV_force_flags_mutable(sv, lp, flags) \
+ ((SvFLAGS(sv) & (SVf_POK|SVf_THINKFIRST)) == SVf_POK \
+ ? ((lp = SvCUR(sv)), SvPVX_mutable(sv)) \
+ : sv_pvn_force_flags(sv, &lp, flags|SV_MUTABLE_RETURN))
+#endif
+#ifndef SvPV_nolen
+# define SvPV_nolen(sv) \
+ ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \
+ ? SvPVX(sv) : sv_2pv_flags(sv, 0, SV_GMAGIC))
+#endif
+#ifndef SvPV_nolen_const
+# define SvPV_nolen_const(sv) \
+ ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \
+ ? SvPVX_const(sv) : sv_2pv_flags(sv, 0, SV_GMAGIC|SV_CONST_RETURN))
+#endif
+#ifndef SvPV_nomg
+# define SvPV_nomg(sv, lp) SvPV_flags(sv, lp, 0)
+#endif
+
+#ifndef SvPV_nomg_const
+# define SvPV_nomg_const(sv, lp) SvPV_flags_const(sv, lp, 0)
+#endif
+
+#ifndef SvPV_nomg_const_nolen
+# define SvPV_nomg_const_nolen(sv) SvPV_flags_const_nolen(sv, 0)
+#endif
+#ifndef SvMAGIC_set
+# define SvMAGIC_set(sv, val) \
+ STMT_START { assert(SvTYPE(sv) >= SVt_PVMG); \
+ (((XPVMG*) SvANY(sv))->xmg_magic = (val)); } STMT_END
+#endif
+
+#if (PERL_BCDVERSION < 0x5009003)
+#ifndef SvPVX_const
+# define SvPVX_const(sv) ((const char*) (0 + SvPVX(sv)))
+#endif
+
+#ifndef SvPVX_mutable
+# define SvPVX_mutable(sv) (0 + SvPVX(sv))
+#endif
+#ifndef SvRV_set
+# define SvRV_set(sv, val) \
+ STMT_START { assert(SvTYPE(sv) >= SVt_RV); \
+ (((XRV*) SvANY(sv))->xrv_rv = (val)); } STMT_END
+#endif
+
+#else
+#ifndef SvPVX_const
+# define SvPVX_const(sv) ((const char*)((sv)->sv_u.svu_pv))
+#endif
+
+#ifndef SvPVX_mutable
+# define SvPVX_mutable(sv) ((sv)->sv_u.svu_pv)
+#endif
+#ifndef SvRV_set
+# define SvRV_set(sv, val) \
+ STMT_START { assert(SvTYPE(sv) >= SVt_RV); \
+ ((sv)->sv_u.svu_rv = (val)); } STMT_END
+#endif
+
+#endif
+#ifndef SvSTASH_set
+# define SvSTASH_set(sv, val) \
+ STMT_START { assert(SvTYPE(sv) >= SVt_PVMG); \
+ (((XPVMG*) SvANY(sv))->xmg_stash = (val)); } STMT_END
+#endif
+
+#if (PERL_BCDVERSION < 0x5004000)
+#ifndef SvUV_set
+# define SvUV_set(sv, val) \
+ STMT_START { assert(SvTYPE(sv) == SVt_IV || SvTYPE(sv) >= SVt_PVIV); \
+ (((XPVIV*) SvANY(sv))->xiv_iv = (IV) (val)); } STMT_END
+#endif
+
+#else
+#ifndef SvUV_set
+# define SvUV_set(sv, val) \
+ STMT_START { assert(SvTYPE(sv) == SVt_IV || SvTYPE(sv) >= SVt_PVIV); \
+ (((XPVUV*) SvANY(sv))->xuv_uv = (val)); } STMT_END
+#endif
+
+#endif
+
+#if (PERL_BCDVERSION >= 0x5004000) && !defined(vnewSVpvf)
+#if defined(NEED_vnewSVpvf)
+static SV * DPPP_(my_vnewSVpvf)(pTHX_ const char * pat, va_list * args);
+static
+#else
+extern SV * DPPP_(my_vnewSVpvf)(pTHX_ const char * pat, va_list * args);
+#endif
+
+#ifdef vnewSVpvf
+# undef vnewSVpvf
+#endif
+#define vnewSVpvf(a,b) DPPP_(my_vnewSVpvf)(aTHX_ a,b)
+#define Perl_vnewSVpvf DPPP_(my_vnewSVpvf)
+
+#if defined(NEED_vnewSVpvf) || defined(NEED_vnewSVpvf_GLOBAL)
+
+SV *
+DPPP_(my_vnewSVpvf)(pTHX_ const char *pat, va_list *args)
+{
+ register SV *sv = newSV(0);
+ sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*));
+ return sv;
+}
+
+#endif
+#endif
+
+#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_vcatpvf)
+# define sv_vcatpvf(sv, pat, args) sv_vcatpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*))
+#endif
+
+#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_vsetpvf)
+# define sv_vsetpvf(sv, pat, args) sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*))
+#endif
+
+#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_catpvf_mg)
+#if defined(NEED_sv_catpvf_mg)
+static void DPPP_(my_sv_catpvf_mg)(pTHX_ SV * sv, const char * pat, ...);
+static
+#else
+extern void DPPP_(my_sv_catpvf_mg)(pTHX_ SV * sv, const char * pat, ...);
+#endif
+
+#define Perl_sv_catpvf_mg DPPP_(my_sv_catpvf_mg)
+
+#if defined(NEED_sv_catpvf_mg) || defined(NEED_sv_catpvf_mg_GLOBAL)
+
+void
+DPPP_(my_sv_catpvf_mg)(pTHX_ SV *sv, const char *pat, ...)
+{
+ va_list args;
+ va_start(args, pat);
+ sv_vcatpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*));
+ SvSETMAGIC(sv);
+ va_end(args);
+}
+
+#endif
+#endif
+
+#ifdef PERL_IMPLICIT_CONTEXT
+#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_catpvf_mg_nocontext)
+#if defined(NEED_sv_catpvf_mg_nocontext)
+static void DPPP_(my_sv_catpvf_mg_nocontext)(SV * sv, const char * pat, ...);
+static
+#else
+extern void DPPP_(my_sv_catpvf_mg_nocontext)(SV * sv, const char * pat, ...);
+#endif
+
+#define sv_catpvf_mg_nocontext DPPP_(my_sv_catpvf_mg_nocontext)
+#define Perl_sv_catpvf_mg_nocontext DPPP_(my_sv_catpvf_mg_nocontext)
+
+#if defined(NEED_sv_catpvf_mg_nocontext) || defined(NEED_sv_catpvf_mg_nocontext_GLOBAL)
+
+void
+DPPP_(my_sv_catpvf_mg_nocontext)(SV *sv, const char *pat, ...)
+{
+ dTHX;
+ va_list args;
+ va_start(args, pat);
+ sv_vcatpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*));
+ SvSETMAGIC(sv);
+ va_end(args);
+}
+
+#endif
+#endif
+#endif
+
+/* sv_catpvf_mg depends on sv_catpvf_mg_nocontext */
+#ifndef sv_catpvf_mg
+# ifdef PERL_IMPLICIT_CONTEXT
+# define sv_catpvf_mg Perl_sv_catpvf_mg_nocontext
+# else
+# define sv_catpvf_mg Perl_sv_catpvf_mg
+# endif
+#endif
+
+#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_vcatpvf_mg)
+# define sv_vcatpvf_mg(sv, pat, args) \
+ STMT_START { \
+ sv_vcatpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*)); \
+ SvSETMAGIC(sv); \
+ } STMT_END
+#endif
+
+#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_setpvf_mg)
+#if defined(NEED_sv_setpvf_mg)
+static void DPPP_(my_sv_setpvf_mg)(pTHX_ SV * sv, const char * pat, ...);
+static
+#else
+extern void DPPP_(my_sv_setpvf_mg)(pTHX_ SV * sv, const char * pat, ...);
+#endif
+
+#define Perl_sv_setpvf_mg DPPP_(my_sv_setpvf_mg)
+
+#if defined(NEED_sv_setpvf_mg) || defined(NEED_sv_setpvf_mg_GLOBAL)
+
+void
+DPPP_(my_sv_setpvf_mg)(pTHX_ SV *sv, const char *pat, ...)
+{
+ va_list args;
+ va_start(args, pat);
+ sv_vsetpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*));
+ SvSETMAGIC(sv);
+ va_end(args);
+}
+
+#endif
+#endif
+
+#ifdef PERL_IMPLICIT_CONTEXT
+#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_setpvf_mg_nocontext)
+#if defined(NEED_sv_setpvf_mg_nocontext)
+static void DPPP_(my_sv_setpvf_mg_nocontext)(SV * sv, const char * pat, ...);
+static
+#else
+extern void DPPP_(my_sv_setpvf_mg_nocontext)(SV * sv, const char * pat, ...);
+#endif
+
+#define sv_setpvf_mg_nocontext DPPP_(my_sv_setpvf_mg_nocontext)
+#define Perl_sv_setpvf_mg_nocontext DPPP_(my_sv_setpvf_mg_nocontext)
+
+#if defined(NEED_sv_setpvf_mg_nocontext) || defined(NEED_sv_setpvf_mg_nocontext_GLOBAL)
+
+void
+DPPP_(my_sv_setpvf_mg_nocontext)(SV *sv, const char *pat, ...)
+{
+ dTHX;
+ va_list args;
+ va_start(args, pat);
+ sv_vsetpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*));
+ SvSETMAGIC(sv);
+ va_end(args);
+}
+
+#endif
+#endif
+#endif
+
+/* sv_setpvf_mg depends on sv_setpvf_mg_nocontext */
+#ifndef sv_setpvf_mg
+# ifdef PERL_IMPLICIT_CONTEXT
+# define sv_setpvf_mg Perl_sv_setpvf_mg_nocontext
+# else
+# define sv_setpvf_mg Perl_sv_setpvf_mg
+# endif
+#endif
+
+#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_vsetpvf_mg)
+# define sv_vsetpvf_mg(sv, pat, args) \
+ STMT_START { \
+ sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*)); \
+ SvSETMAGIC(sv); \
+ } STMT_END
+#endif
+
+#ifndef newSVpvn_share
+
+#if defined(NEED_newSVpvn_share)
+static SV * DPPP_(my_newSVpvn_share)(pTHX_ const char *src, I32 len, U32 hash);
+static
+#else
+extern SV * DPPP_(my_newSVpvn_share)(pTHX_ const char *src, I32 len, U32 hash);
+#endif
+
+#ifdef newSVpvn_share
+# undef newSVpvn_share
+#endif
+#define newSVpvn_share(a,b,c) DPPP_(my_newSVpvn_share)(aTHX_ a,b,c)
+#define Perl_newSVpvn_share DPPP_(my_newSVpvn_share)
+
+#if defined(NEED_newSVpvn_share) || defined(NEED_newSVpvn_share_GLOBAL)
+
+SV *
+DPPP_(my_newSVpvn_share)(pTHX_ const char *src, I32 len, U32 hash)
+{
+ SV *sv;
+ if (len < 0)
+ len = -len;
+ if (!hash)
+ PERL_HASH(hash, (char*) src, len);
+ sv = newSVpvn((char *) src, len);
+ sv_upgrade(sv, SVt_PVIV);
+ SvIVX(sv) = hash;
+ SvREADONLY_on(sv);
+ SvPOK_on(sv);
+ return sv;
+}
+
+#endif
+
+#endif
+#ifndef SvSHARED_HASH
+# define SvSHARED_HASH(sv) (0 + SvUVX(sv))
+#endif
+#ifndef WARN_ALL
+# define WARN_ALL 0
+#endif
+
+#ifndef WARN_CLOSURE
+# define WARN_CLOSURE 1
+#endif
+
+#ifndef WARN_DEPRECATED
+# define WARN_DEPRECATED 2
+#endif
+
+#ifndef WARN_EXITING
+# define WARN_EXITING 3
+#endif
+
+#ifndef WARN_GLOB
+# define WARN_GLOB 4
+#endif
+
+#ifndef WARN_IO
+# define WARN_IO 5
+#endif
+
+#ifndef WARN_CLOSED
+# define WARN_CLOSED 6
+#endif
+
+#ifndef WARN_EXEC
+# define WARN_EXEC 7
+#endif
+
+#ifndef WARN_LAYER
+# define WARN_LAYER 8
+#endif
+
+#ifndef WARN_NEWLINE
+# define WARN_NEWLINE 9
+#endif
+
+#ifndef WARN_PIPE
+# define WARN_PIPE 10
+#endif
+
+#ifndef WARN_UNOPENED
+# define WARN_UNOPENED 11
+#endif
+
+#ifndef WARN_MISC
+# define WARN_MISC 12
+#endif
+
+#ifndef WARN_NUMERIC
+# define WARN_NUMERIC 13
+#endif
+
+#ifndef WARN_ONCE
+# define WARN_ONCE 14
+#endif
+
+#ifndef WARN_OVERFLOW
+# define WARN_OVERFLOW 15
+#endif
+
+#ifndef WARN_PACK
+# define WARN_PACK 16
+#endif
+
+#ifndef WARN_PORTABLE
+# define WARN_PORTABLE 17
+#endif
+
+#ifndef WARN_RECURSION
+# define WARN_RECURSION 18
+#endif
+
+#ifndef WARN_REDEFINE
+# define WARN_REDEFINE 19
+#endif
+
+#ifndef WARN_REGEXP
+# define WARN_REGEXP 20
+#endif
+
+#ifndef WARN_SEVERE
+# define WARN_SEVERE 21
+#endif
+
+#ifndef WARN_DEBUGGING
+# define WARN_DEBUGGING 22
+#endif
+
+#ifndef WARN_INPLACE
+# define WARN_INPLACE 23
+#endif
+
+#ifndef WARN_INTERNAL
+# define WARN_INTERNAL 24
+#endif
+
+#ifndef WARN_MALLOC
+# define WARN_MALLOC 25
+#endif
+
+#ifndef WARN_SIGNAL
+# define WARN_SIGNAL 26
+#endif
+
+#ifndef WARN_SUBSTR
+# define WARN_SUBSTR 27
+#endif
+
+#ifndef WARN_SYNTAX
+# define WARN_SYNTAX 28
+#endif
+
+#ifndef WARN_AMBIGUOUS
+# define WARN_AMBIGUOUS 29
+#endif
+
+#ifndef WARN_BAREWORD
+# define WARN_BAREWORD 30
+#endif
+
+#ifndef WARN_DIGIT
+# define WARN_DIGIT 31
+#endif
+
+#ifndef WARN_PARENTHESIS
+# define WARN_PARENTHESIS 32
+#endif
+
+#ifndef WARN_PRECEDENCE
+# define WARN_PRECEDENCE 33
+#endif
+
+#ifndef WARN_PRINTF
+# define WARN_PRINTF 34
+#endif
+
+#ifndef WARN_PROTOTYPE
+# define WARN_PROTOTYPE 35
+#endif
+
+#ifndef WARN_QW
+# define WARN_QW 36
+#endif
+
+#ifndef WARN_RESERVED
+# define WARN_RESERVED 37
+#endif
+
+#ifndef WARN_SEMICOLON
+# define WARN_SEMICOLON 38
+#endif
+
+#ifndef WARN_TAINT
+# define WARN_TAINT 39
+#endif
+
+#ifndef WARN_THREADS
+# define WARN_THREADS 40
+#endif
+
+#ifndef WARN_UNINITIALIZED
+# define WARN_UNINITIALIZED 41
+#endif
+
+#ifndef WARN_UNPACK
+# define WARN_UNPACK 42
+#endif
+
+#ifndef WARN_UNTIE
+# define WARN_UNTIE 43
+#endif
+
+#ifndef WARN_UTF8
+# define WARN_UTF8 44
+#endif
+
+#ifndef WARN_VOID
+# define WARN_VOID 45
+#endif
+
+#ifndef WARN_ASSERTIONS
+# define WARN_ASSERTIONS 46
+#endif
+#ifndef packWARN
+# define packWARN(a) (a)
+#endif
+
+#ifndef ckWARN
+# ifdef G_WARN_ON
+# define ckWARN(a) (PL_dowarn & G_WARN_ON)
+# else
+# define ckWARN(a) PL_dowarn
+# endif
+#endif
+
+#if (PERL_BCDVERSION >= 0x5004000) && !defined(warner)
+#if defined(NEED_warner)
+static void DPPP_(my_warner)(U32 err, const char *pat, ...);
+static
+#else
+extern void DPPP_(my_warner)(U32 err, const char *pat, ...);
+#endif
+
+#define Perl_warner DPPP_(my_warner)
+
+#if defined(NEED_warner) || defined(NEED_warner_GLOBAL)
+
+void
+DPPP_(my_warner)(U32 err, const char *pat, ...)
+{
+ SV *sv;
+ va_list args;
+
+ PERL_UNUSED_ARG(err);
+
+ va_start(args, pat);
+ sv = vnewSVpvf(pat, &args);
+ va_end(args);
+ sv_2mortal(sv);
+ warn("%s", SvPV_nolen(sv));
+}
+
+#define warner Perl_warner
+
+#define Perl_warner_nocontext Perl_warner
+
+#endif
+#endif
+
+/* concatenating with "" ensures that only literal strings are accepted as argument
+ * note that STR_WITH_LEN() can't be used as argument to macros or functions that
+ * under some configurations might be macros
+ */
+#ifndef STR_WITH_LEN
+# define STR_WITH_LEN(s) (s ""), (sizeof(s)-1)
+#endif
+#ifndef newSVpvs
+# define newSVpvs(str) newSVpvn(str "", sizeof(str) - 1)
+#endif
+
+#ifndef sv_catpvs
+# define sv_catpvs(sv, str) sv_catpvn(sv, str "", sizeof(str) - 1)
+#endif
+
+#ifndef sv_setpvs
+# define sv_setpvs(sv, str) sv_setpvn(sv, str "", sizeof(str) - 1)
+#endif
+
+#ifndef hv_fetchs
+# define hv_fetchs(hv, key, lval) hv_fetch(hv, key "", sizeof(key) - 1, lval)
+#endif
+
+#ifndef hv_stores
+# define hv_stores(hv, key, val) hv_store(hv, key "", sizeof(key) - 1, val, 0)
+#endif
+#ifndef SvGETMAGIC
+# define SvGETMAGIC(x) STMT_START { if (SvGMAGICAL(x)) mg_get(x); } STMT_END
+#endif
+#ifndef PERL_MAGIC_sv
+# define PERL_MAGIC_sv '\0'
+#endif
+
+#ifndef PERL_MAGIC_overload
+# define PERL_MAGIC_overload 'A'
+#endif
+
+#ifndef PERL_MAGIC_overload_elem
+# define PERL_MAGIC_overload_elem 'a'
+#endif
+
+#ifndef PERL_MAGIC_overload_table
+# define PERL_MAGIC_overload_table 'c'
+#endif
+
+#ifndef PERL_MAGIC_bm
+# define PERL_MAGIC_bm 'B'
+#endif
+
+#ifndef PERL_MAGIC_regdata
+# define PERL_MAGIC_regdata 'D'
+#endif
+
+#ifndef PERL_MAGIC_regdatum
+# define PERL_MAGIC_regdatum 'd'
+#endif
+
+#ifndef PERL_MAGIC_env
+# define PERL_MAGIC_env 'E'
+#endif
+
+#ifndef PERL_MAGIC_envelem
+# define PERL_MAGIC_envelem 'e'
+#endif
+
+#ifndef PERL_MAGIC_fm
+# define PERL_MAGIC_fm 'f'
+#endif
+
+#ifndef PERL_MAGIC_regex_global
+# define PERL_MAGIC_regex_global 'g'
+#endif
+
+#ifndef PERL_MAGIC_isa
+# define PERL_MAGIC_isa 'I'
+#endif
+
+#ifndef PERL_MAGIC_isaelem
+# define PERL_MAGIC_isaelem 'i'
+#endif
+
+#ifndef PERL_MAGIC_nkeys
+# define PERL_MAGIC_nkeys 'k'
+#endif
+
+#ifndef PERL_MAGIC_dbfile
+# define PERL_MAGIC_dbfile 'L'
+#endif
+
+#ifndef PERL_MAGIC_dbline
+# define PERL_MAGIC_dbline 'l'
+#endif
+
+#ifndef PERL_MAGIC_mutex
+# define PERL_MAGIC_mutex 'm'
+#endif
+
+#ifndef PERL_MAGIC_shared
+# define PERL_MAGIC_shared 'N'
+#endif
+
+#ifndef PERL_MAGIC_shared_scalar
+# define PERL_MAGIC_shared_scalar 'n'
+#endif
+
+#ifndef PERL_MAGIC_collxfrm
+# define PERL_MAGIC_collxfrm 'o'
+#endif
+
+#ifndef PERL_MAGIC_tied
+# define PERL_MAGIC_tied 'P'
+#endif
+
+#ifndef PERL_MAGIC_tiedelem
+# define PERL_MAGIC_tiedelem 'p'
+#endif
+
+#ifndef PERL_MAGIC_tiedscalar
+# define PERL_MAGIC_tiedscalar 'q'
+#endif
+
+#ifndef PERL_MAGIC_qr
+# define PERL_MAGIC_qr 'r'
+#endif
+
+#ifndef PERL_MAGIC_sig
+# define PERL_MAGIC_sig 'S'
+#endif
+
+#ifndef PERL_MAGIC_sigelem
+# define PERL_MAGIC_sigelem 's'
+#endif
+
+#ifndef PERL_MAGIC_taint
+# define PERL_MAGIC_taint 't'
+#endif
+
+#ifndef PERL_MAGIC_uvar
+# define PERL_MAGIC_uvar 'U'
+#endif
+
+#ifndef PERL_MAGIC_uvar_elem
+# define PERL_MAGIC_uvar_elem 'u'
+#endif
+
+#ifndef PERL_MAGIC_vstring
+# define PERL_MAGIC_vstring 'V'
+#endif
+
+#ifndef PERL_MAGIC_vec
+# define PERL_MAGIC_vec 'v'
+#endif
+
+#ifndef PERL_MAGIC_utf8
+# define PERL_MAGIC_utf8 'w'
+#endif
+
+#ifndef PERL_MAGIC_substr
+# define PERL_MAGIC_substr 'x'
+#endif
+
+#ifndef PERL_MAGIC_defelem
+# define PERL_MAGIC_defelem 'y'
+#endif
+
+#ifndef PERL_MAGIC_glob
+# define PERL_MAGIC_glob '*'
+#endif
+
+#ifndef PERL_MAGIC_arylen
+# define PERL_MAGIC_arylen '#'
+#endif
+
+#ifndef PERL_MAGIC_pos
+# define PERL_MAGIC_pos '.'
+#endif
+
+#ifndef PERL_MAGIC_backref
+# define PERL_MAGIC_backref '<'
+#endif
+
+#ifndef PERL_MAGIC_ext
+# define PERL_MAGIC_ext '~'
+#endif
+
+/* That's the best we can do... */
+#ifndef sv_catpvn_nomg
+# define sv_catpvn_nomg sv_catpvn
+#endif
+
+#ifndef sv_catsv_nomg
+# define sv_catsv_nomg sv_catsv
+#endif
+
+#ifndef sv_setsv_nomg
+# define sv_setsv_nomg sv_setsv
+#endif
+
+#ifndef sv_pvn_nomg
+# define sv_pvn_nomg sv_pvn
+#endif
+
+#ifndef SvIV_nomg
+# define SvIV_nomg SvIV
+#endif
+
+#ifndef SvUV_nomg
+# define SvUV_nomg SvUV
+#endif
+
+#ifndef sv_catpv_mg
+# define sv_catpv_mg(sv, ptr) \
+ STMT_START { \
+ SV *TeMpSv = sv; \
+ sv_catpv(TeMpSv,ptr); \
+ SvSETMAGIC(TeMpSv); \
+ } STMT_END
+#endif
+
+#ifndef sv_catpvn_mg
+# define sv_catpvn_mg(sv, ptr, len) \
+ STMT_START { \
+ SV *TeMpSv = sv; \
+ sv_catpvn(TeMpSv,ptr,len); \
+ SvSETMAGIC(TeMpSv); \
+ } STMT_END
+#endif
+
+#ifndef sv_catsv_mg
+# define sv_catsv_mg(dsv, ssv) \
+ STMT_START { \
+ SV *TeMpSv = dsv; \
+ sv_catsv(TeMpSv,ssv); \
+ SvSETMAGIC(TeMpSv); \
+ } STMT_END
+#endif
+
+#ifndef sv_setiv_mg
+# define sv_setiv_mg(sv, i) \
+ STMT_START { \
+ SV *TeMpSv = sv; \
+ sv_setiv(TeMpSv,i); \
+ SvSETMAGIC(TeMpSv); \
+ } STMT_END
+#endif
+
+#ifndef sv_setnv_mg
+# define sv_setnv_mg(sv, num) \
+ STMT_START { \
+ SV *TeMpSv = sv; \
+ sv_setnv(TeMpSv,num); \
+ SvSETMAGIC(TeMpSv); \
+ } STMT_END
+#endif
+
+#ifndef sv_setpv_mg
+# define sv_setpv_mg(sv, ptr) \
+ STMT_START { \
+ SV *TeMpSv = sv; \
+ sv_setpv(TeMpSv,ptr); \
+ SvSETMAGIC(TeMpSv); \
+ } STMT_END
+#endif
+
+#ifndef sv_setpvn_mg
+# define sv_setpvn_mg(sv, ptr, len) \
+ STMT_START { \
+ SV *TeMpSv = sv; \
+ sv_setpvn(TeMpSv,ptr,len); \
+ SvSETMAGIC(TeMpSv); \
+ } STMT_END
+#endif
+
+#ifndef sv_setsv_mg
+# define sv_setsv_mg(dsv, ssv) \
+ STMT_START { \
+ SV *TeMpSv = dsv; \
+ sv_setsv(TeMpSv,ssv); \
+ SvSETMAGIC(TeMpSv); \
+ } STMT_END
+#endif
+
+#ifndef sv_setuv_mg
+# define sv_setuv_mg(sv, i) \
+ STMT_START { \
+ SV *TeMpSv = sv; \
+ sv_setuv(TeMpSv,i); \
+ SvSETMAGIC(TeMpSv); \
+ } STMT_END
+#endif
+
+#ifndef sv_usepvn_mg
+# define sv_usepvn_mg(sv, ptr, len) \
+ STMT_START { \
+ SV *TeMpSv = sv; \
+ sv_usepvn(TeMpSv,ptr,len); \
+ SvSETMAGIC(TeMpSv); \
+ } STMT_END
+#endif
+#ifndef SvVSTRING_mg
+# define SvVSTRING_mg(sv) (SvMAGICAL(sv) ? mg_find(sv, PERL_MAGIC_vstring) : NULL)
+#endif
+
+/* Hint: sv_magic_portable
+ * This is a compatibility function that is only available with
+ * Devel::PPPort. It is NOT in the perl core.
+ * Its purpose is to mimic the 5.8.0 behaviour of sv_magic() when
+ * it is being passed a name pointer with namlen == 0. In that
+ * case, perl 5.8.0 and later store the pointer, not a copy of it.
+ * The compatibility can be provided back to perl 5.004. With
+ * earlier versions, the code will not compile.
+ */
+
+#if (PERL_BCDVERSION < 0x5004000)
+
+ /* code that uses sv_magic_portable will not compile */
+
+#elif (PERL_BCDVERSION < 0x5008000)
+
+# define sv_magic_portable(sv, obj, how, name, namlen) \
+ STMT_START { \
+ SV *SvMp_sv = (sv); \
+ char *SvMp_name = (char *) (name); \
+ I32 SvMp_namlen = (namlen); \
+ if (SvMp_name && SvMp_namlen == 0) \
+ { \
+ MAGIC *mg; \
+ sv_magic(SvMp_sv, obj, how, 0, 0); \
+ mg = SvMAGIC(SvMp_sv); \
+ mg->mg_len = -42; /* XXX: this is the tricky part */ \
+ mg->mg_ptr = SvMp_name; \
+ } \
+ else \
+ { \
+ sv_magic(SvMp_sv, obj, how, SvMp_name, SvMp_namlen); \
+ } \
+ } STMT_END
+
+#else
+
+# define sv_magic_portable(a, b, c, d, e) sv_magic(a, b, c, d, e)
+
+#endif
+
+#ifdef USE_ITHREADS
+#ifndef CopFILE
+# define CopFILE(c) ((c)->cop_file)
+#endif
+
+#ifndef CopFILEGV
+# define CopFILEGV(c) (CopFILE(c) ? gv_fetchfile(CopFILE(c)) : Nullgv)
+#endif
+
+#ifndef CopFILE_set
+# define CopFILE_set(c,pv) ((c)->cop_file = savepv(pv))
+#endif
+
+#ifndef CopFILESV
+# define CopFILESV(c) (CopFILE(c) ? GvSV(gv_fetchfile(CopFILE(c))) : Nullsv)
+#endif
+
+#ifndef CopFILEAV
+# define CopFILEAV(c) (CopFILE(c) ? GvAV(gv_fetchfile(CopFILE(c))) : Nullav)
+#endif
+
+#ifndef CopSTASHPV
+# define CopSTASHPV(c) ((c)->cop_stashpv)
+#endif
+
+#ifndef CopSTASHPV_set
+# define CopSTASHPV_set(c,pv) ((c)->cop_stashpv = ((pv) ? savepv(pv) : Nullch))
+#endif
+
+#ifndef CopSTASH
+# define CopSTASH(c) (CopSTASHPV(c) ? gv_stashpv(CopSTASHPV(c),GV_ADD) : Nullhv)
+#endif
+
+#ifndef CopSTASH_set
+# define CopSTASH_set(c,hv) CopSTASHPV_set(c, (hv) ? HvNAME(hv) : Nullch)
+#endif
+
+#ifndef CopSTASH_eq
+# define CopSTASH_eq(c,hv) ((hv) && (CopSTASHPV(c) == HvNAME(hv) \
+ || (CopSTASHPV(c) && HvNAME(hv) \
+ && strEQ(CopSTASHPV(c), HvNAME(hv)))))
+#endif
+
+#else
+#ifndef CopFILEGV
+# define CopFILEGV(c) ((c)->cop_filegv)
+#endif
+
+#ifndef CopFILEGV_set
+# define CopFILEGV_set(c,gv) ((c)->cop_filegv = (GV*)SvREFCNT_inc(gv))
+#endif
+
+#ifndef CopFILE_set
+# define CopFILE_set(c,pv) CopFILEGV_set((c), gv_fetchfile(pv))
+#endif
+
+#ifndef CopFILESV
+# define CopFILESV(c) (CopFILEGV(c) ? GvSV(CopFILEGV(c)) : Nullsv)
+#endif
+
+#ifndef CopFILEAV
+# define CopFILEAV(c) (CopFILEGV(c) ? GvAV(CopFILEGV(c)) : Nullav)
+#endif
+
+#ifndef CopFILE
+# define CopFILE(c) (CopFILESV(c) ? SvPVX(CopFILESV(c)) : Nullch)
+#endif
+
+#ifndef CopSTASH
+# define CopSTASH(c) ((c)->cop_stash)
+#endif
+
+#ifndef CopSTASH_set
+# define CopSTASH_set(c,hv) ((c)->cop_stash = (hv))
+#endif
+
+#ifndef CopSTASHPV
+# define CopSTASHPV(c) (CopSTASH(c) ? HvNAME(CopSTASH(c)) : Nullch)
+#endif
+
+#ifndef CopSTASHPV_set
+# define CopSTASHPV_set(c,pv) CopSTASH_set((c), gv_stashpv(pv,GV_ADD))
+#endif
+
+#ifndef CopSTASH_eq
+# define CopSTASH_eq(c,hv) (CopSTASH(c) == (hv))
+#endif
+
+#endif /* USE_ITHREADS */
+#ifndef IN_PERL_COMPILETIME
+# define IN_PERL_COMPILETIME (PL_curcop == &PL_compiling)
+#endif
+
+#ifndef IN_LOCALE_RUNTIME
+# define IN_LOCALE_RUNTIME (PL_curcop->op_private & HINT_LOCALE)
+#endif
+
+#ifndef IN_LOCALE_COMPILETIME
+# define IN_LOCALE_COMPILETIME (PL_hints & HINT_LOCALE)
+#endif
+
+#ifndef IN_LOCALE
+# define IN_LOCALE (IN_PERL_COMPILETIME ? IN_LOCALE_COMPILETIME : IN_LOCALE_RUNTIME)
+#endif
+#ifndef IS_NUMBER_IN_UV
+# define IS_NUMBER_IN_UV 0x01
+#endif
+
+#ifndef IS_NUMBER_GREATER_THAN_UV_MAX
+# define IS_NUMBER_GREATER_THAN_UV_MAX 0x02
+#endif
+
+#ifndef IS_NUMBER_NOT_INT
+# define IS_NUMBER_NOT_INT 0x04
+#endif
+
+#ifndef IS_NUMBER_NEG
+# define IS_NUMBER_NEG 0x08
+#endif
+
+#ifndef IS_NUMBER_INFINITY
+# define IS_NUMBER_INFINITY 0x10
+#endif
+
+#ifndef IS_NUMBER_NAN
+# define IS_NUMBER_NAN 0x20
+#endif
+#ifndef GROK_NUMERIC_RADIX
+# define GROK_NUMERIC_RADIX(sp, send) grok_numeric_radix(sp, send)
+#endif
+#ifndef PERL_SCAN_GREATER_THAN_UV_MAX
+# define PERL_SCAN_GREATER_THAN_UV_MAX 0x02
+#endif
+
+#ifndef PERL_SCAN_SILENT_ILLDIGIT
+# define PERL_SCAN_SILENT_ILLDIGIT 0x04
+#endif
+
+#ifndef PERL_SCAN_ALLOW_UNDERSCORES
+# define PERL_SCAN_ALLOW_UNDERSCORES 0x01
+#endif
+
+#ifndef PERL_SCAN_DISALLOW_PREFIX
+# define PERL_SCAN_DISALLOW_PREFIX 0x02
+#endif
+
+#ifndef grok_numeric_radix
+#if defined(NEED_grok_numeric_radix)
+static bool DPPP_(my_grok_numeric_radix)(pTHX_ const char ** sp, const char * send);
+static
+#else
+extern bool DPPP_(my_grok_numeric_radix)(pTHX_ const char ** sp, const char * send);
+#endif
+
+#ifdef grok_numeric_radix
+# undef grok_numeric_radix
+#endif
+#define grok_numeric_radix(a,b) DPPP_(my_grok_numeric_radix)(aTHX_ a,b)
+#define Perl_grok_numeric_radix DPPP_(my_grok_numeric_radix)
+
+#if defined(NEED_grok_numeric_radix) || defined(NEED_grok_numeric_radix_GLOBAL)
+bool
+DPPP_(my_grok_numeric_radix)(pTHX_ const char **sp, const char *send)
+{
+#ifdef USE_LOCALE_NUMERIC
+#ifdef PL_numeric_radix_sv
+ if (PL_numeric_radix_sv && IN_LOCALE) {
+ STRLEN len;
+ char* radix = SvPV(PL_numeric_radix_sv, len);
+ if (*sp + len <= send && memEQ(*sp, radix, len)) {
+ *sp += len;
+ return TRUE;
+ }
+ }
+#else
+ /* older perls don't have PL_numeric_radix_sv so the radix
+ * must manually be requested from locale.h
+ */
+#include <locale.h>
+ dTHR; /* needed for older threaded perls */
+ struct lconv *lc = localeconv();
+ char *radix = lc->decimal_point;
+ if (radix && IN_LOCALE) {
+ STRLEN len = strlen(radix);
+ if (*sp + len <= send && memEQ(*sp, radix, len)) {
+ *sp += len;
+ return TRUE;
+ }
+ }
+#endif
+#endif /* USE_LOCALE_NUMERIC */
+ /* always try "." if numeric radix didn't match because
+ * we may have data from different locales mixed */
+ if (*sp < send && **sp == '.') {
+ ++*sp;
+ return TRUE;
+ }
+ return FALSE;
+}
+#endif
+#endif
+
+#ifndef grok_number
+#if defined(NEED_grok_number)
+static int DPPP_(my_grok_number)(pTHX_ const char * pv, STRLEN len, UV * valuep);
+static
+#else
+extern int DPPP_(my_grok_number)(pTHX_ const char * pv, STRLEN len, UV * valuep);
+#endif
+
+#ifdef grok_number
+# undef grok_number
+#endif
+#define grok_number(a,b,c) DPPP_(my_grok_number)(aTHX_ a,b,c)
+#define Perl_grok_number DPPP_(my_grok_number)
+
+#if defined(NEED_grok_number) || defined(NEED_grok_number_GLOBAL)
+int
+DPPP_(my_grok_number)(pTHX_ const char *pv, STRLEN len, UV *valuep)
+{
+ const char *s = pv;
+ const char *send = pv + len;
+ const UV max_div_10 = UV_MAX / 10;
+ const char max_mod_10 = UV_MAX % 10;
+ int numtype = 0;
+ int sawinf = 0;
+ int sawnan = 0;
+
+ while (s < send && isSPACE(*s))
+ s++;
+ if (s == send) {
+ return 0;
+ } else if (*s == '-') {
+ s++;
+ numtype = IS_NUMBER_NEG;
+ }
+ else if (*s == '+')
+ s++;
+
+ if (s == send)
+ return 0;
+
+ /* next must be digit or the radix separator or beginning of infinity */
+ if (isDIGIT(*s)) {
+ /* UVs are at least 32 bits, so the first 9 decimal digits cannot
+ overflow. */
+ UV value = *s - '0';
+ /* This construction seems to be more optimiser friendly.
+ (without it gcc does the isDIGIT test and the *s - '0' separately)
+ With it gcc on arm is managing 6 instructions (6 cycles) per digit.
+ In theory the optimiser could deduce how far to unroll the loop
+ before checking for overflow. */
+ if (++s < send) {
+ int digit = *s - '0';
+ if (digit >= 0 && digit <= 9) {
+ value = value * 10 + digit;
+ if (++s < send) {
+ digit = *s - '0';
+ if (digit >= 0 && digit <= 9) {
+ value = value * 10 + digit;
+ if (++s < send) {
+ digit = *s - '0';
+ if (digit >= 0 && digit <= 9) {
+ value = value * 10 + digit;
+ if (++s < send) {
+ digit = *s - '0';
+ if (digit >= 0 && digit <= 9) {
+ value = value * 10 + digit;
+ if (++s < send) {
+ digit = *s - '0';
+ if (digit >= 0 && digit <= 9) {
+ value = value * 10 + digit;
+ if (++s < send) {
+ digit = *s - '0';
+ if (digit >= 0 && digit <= 9) {
+ value = value * 10 + digit;
+ if (++s < send) {
+ digit = *s - '0';
+ if (digit >= 0 && digit <= 9) {
+ value = value * 10 + digit;
+ if (++s < send) {
+ digit = *s - '0';
+ if (digit >= 0 && digit <= 9) {
+ value = value * 10 + digit;
+ if (++s < send) {
+ /* Now got 9 digits, so need to check
+ each time for overflow. */
+ digit = *s - '0';
+ while (digit >= 0 && digit <= 9
+ && (value < max_div_10
+ || (value == max_div_10
+ && digit <= max_mod_10))) {
+ value = value * 10 + digit;
+ if (++s < send)
+ digit = *s - '0';
+ else
+ break;
+ }
+ if (digit >= 0 && digit <= 9
+ && (s < send)) {
+ /* value overflowed.
+ skip the remaining digits, don't
+ worry about setting *valuep. */
+ do {
+ s++;
+ } while (s < send && isDIGIT(*s));
+ numtype |=
+ IS_NUMBER_GREATER_THAN_UV_MAX;
+ goto skip_value;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ numtype |= IS_NUMBER_IN_UV;
+ if (valuep)
+ *valuep = value;
+
+ skip_value:
+ if (GROK_NUMERIC_RADIX(&s, send)) {
+ numtype |= IS_NUMBER_NOT_INT;
+ while (s < send && isDIGIT(*s)) /* optional digits after the radix */
+ s++;
+ }
+ }
+ else if (GROK_NUMERIC_RADIX(&s, send)) {
+ numtype |= IS_NUMBER_NOT_INT | IS_NUMBER_IN_UV; /* valuep assigned below */
+ /* no digits before the radix means we need digits after it */
+ if (s < send && isDIGIT(*s)) {
+ do {
+ s++;
+ } while (s < send && isDIGIT(*s));
+ if (valuep) {
+ /* integer approximation is valid - it's 0. */
+ *valuep = 0;
+ }
+ }
+ else
+ return 0;
+ } else if (*s == 'I' || *s == 'i') {
+ s++; if (s == send || (*s != 'N' && *s != 'n')) return 0;
+ s++; if (s == send || (*s != 'F' && *s != 'f')) return 0;
+ s++; if (s < send && (*s == 'I' || *s == 'i')) {
+ s++; if (s == send || (*s != 'N' && *s != 'n')) return 0;
+ s++; if (s == send || (*s != 'I' && *s != 'i')) return 0;
+ s++; if (s == send || (*s != 'T' && *s != 't')) return 0;
+ s++; if (s == send || (*s != 'Y' && *s != 'y')) return 0;
+ s++;
+ }
+ sawinf = 1;
+ } else if (*s == 'N' || *s == 'n') {
+ /* XXX TODO: There are signaling NaNs and quiet NaNs. */
+ s++; if (s == send || (*s != 'A' && *s != 'a')) return 0;
+ s++; if (s == send || (*s != 'N' && *s != 'n')) return 0;
+ s++;
+ sawnan = 1;
+ } else
+ return 0;
+
+ if (sawinf) {
+ numtype &= IS_NUMBER_NEG; /* Keep track of sign */
+ numtype |= IS_NUMBER_INFINITY | IS_NUMBER_NOT_INT;
+ } else if (sawnan) {
+ numtype &= IS_NUMBER_NEG; /* Keep track of sign */
+ numtype |= IS_NUMBER_NAN | IS_NUMBER_NOT_INT;
+ } else if (s < send) {
+ /* we can have an optional exponent part */
+ if (*s == 'e' || *s == 'E') {
+ /* The only flag we keep is sign. Blow away any "it's UV" */
+ numtype &= IS_NUMBER_NEG;
+ numtype |= IS_NUMBER_NOT_INT;
+ s++;
+ if (s < send && (*s == '-' || *s == '+'))
+ s++;
+ if (s < send && isDIGIT(*s)) {
+ do {
+ s++;
+ } while (s < send && isDIGIT(*s));
+ }
+ else
+ return 0;
+ }
+ }
+ while (s < send && isSPACE(*s))
+ s++;
+ if (s >= send)
+ return numtype;
+ if (len == 10 && memEQ(pv, "0 but true", 10)) {
+ if (valuep)
+ *valuep = 0;
+ return IS_NUMBER_IN_UV;
+ }
+ return 0;
+}
+#endif
+#endif
+
+/*
+ * The grok_* routines have been modified to use warn() instead of
+ * Perl_warner(). Also, 'hexdigit' was the former name of PL_hexdigit,
+ * which is why the stack variable has been renamed to 'xdigit'.
+ */
+
+#ifndef grok_bin
+#if defined(NEED_grok_bin)
+static UV DPPP_(my_grok_bin)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result);
+static
+#else
+extern UV DPPP_(my_grok_bin)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result);
+#endif
+
+#ifdef grok_bin
+# undef grok_bin
+#endif
+#define grok_bin(a,b,c,d) DPPP_(my_grok_bin)(aTHX_ a,b,c,d)
+#define Perl_grok_bin DPPP_(my_grok_bin)
+
+#if defined(NEED_grok_bin) || defined(NEED_grok_bin_GLOBAL)
+UV
+DPPP_(my_grok_bin)(pTHX_ const char *start, STRLEN *len_p, I32 *flags, NV *result)
+{
+ const char *s = start;
+ STRLEN len = *len_p;
+ UV value = 0;
+ NV value_nv = 0;
+
+ const UV max_div_2 = UV_MAX / 2;
+ bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES;
+ bool overflowed = FALSE;
+
+ if (!(*flags & PERL_SCAN_DISALLOW_PREFIX)) {
+ /* strip off leading b or 0b.
+ for compatibility silently suffer "b" and "0b" as valid binary
+ numbers. */
+ if (len >= 1) {
+ if (s[0] == 'b') {
+ s++;
+ len--;
+ }
+ else if (len >= 2 && s[0] == '0' && s[1] == 'b') {
+ s+=2;
+ len-=2;
+ }
+ }
+ }
+
+ for (; len-- && *s; s++) {
+ char bit = *s;
+ if (bit == '0' || bit == '1') {
+ /* Write it in this wonky order with a goto to attempt to get the
+ compiler to make the common case integer-only loop pretty tight.
+ With gcc seems to be much straighter code than old scan_bin. */
+ redo:
+ if (!overflowed) {
+ if (value <= max_div_2) {
+ value = (value << 1) | (bit - '0');
+ continue;
+ }
+ /* Bah. We're just overflowed. */
+ warn("Integer overflow in binary number");
+ overflowed = TRUE;
+ value_nv = (NV) value;
+ }
+ value_nv *= 2.0;
+ /* If an NV has not enough bits in its mantissa to
+ * represent a UV this summing of small low-order numbers
+ * is a waste of time (because the NV cannot preserve
+ * the low-order bits anyway): we could just remember when
+ * did we overflow and in the end just multiply value_nv by the
+ * right amount. */
+ value_nv += (NV)(bit - '0');
+ continue;
+ }
+ if (bit == '_' && len && allow_underscores && (bit = s[1])
+ && (bit == '0' || bit == '1'))
+ {
+ --len;
+ ++s;
+ goto redo;
+ }
+ if (!(*flags & PERL_SCAN_SILENT_ILLDIGIT))
+ warn("Illegal binary digit '%c' ignored", *s);
+ break;
+ }
+
+ if ( ( overflowed && value_nv > 4294967295.0)
+#if UVSIZE > 4
+ || (!overflowed && value > 0xffffffff )
+#endif
+ ) {
+ warn("Binary number > 0b11111111111111111111111111111111 non-portable");
+ }
+ *len_p = s - start;
+ if (!overflowed) {
+ *flags = 0;
+ return value;
+ }
+ *flags = PERL_SCAN_GREATER_THAN_UV_MAX;
+ if (result)
+ *result = value_nv;
+ return UV_MAX;
+}
+#endif
+#endif
+
+#ifndef grok_hex
+#if defined(NEED_grok_hex)
+static UV DPPP_(my_grok_hex)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result);
+static
+#else
+extern UV DPPP_(my_grok_hex)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result);
+#endif
+
+#ifdef grok_hex
+# undef grok_hex
+#endif
+#define grok_hex(a,b,c,d) DPPP_(my_grok_hex)(aTHX_ a,b,c,d)
+#define Perl_grok_hex DPPP_(my_grok_hex)
+
+#if defined(NEED_grok_hex) || defined(NEED_grok_hex_GLOBAL)
+UV
+DPPP_(my_grok_hex)(pTHX_ const char *start, STRLEN *len_p, I32 *flags, NV *result)
+{
+ const char *s = start;
+ STRLEN len = *len_p;
+ UV value = 0;
+ NV value_nv = 0;
+
+ const UV max_div_16 = UV_MAX / 16;
+ bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES;
+ bool overflowed = FALSE;
+ const char *xdigit;
+
+ if (!(*flags & PERL_SCAN_DISALLOW_PREFIX)) {
+ /* strip off leading x or 0x.
+ for compatibility silently suffer "x" and "0x" as valid hex numbers.
+ */
+ if (len >= 1) {
+ if (s[0] == 'x') {
+ s++;
+ len--;
+ }
+ else if (len >= 2 && s[0] == '0' && s[1] == 'x') {
+ s+=2;
+ len-=2;
+ }
+ }
+ }
+
+ for (; len-- && *s; s++) {
+ xdigit = strchr((char *) PL_hexdigit, *s);
+ if (xdigit) {
+ /* Write it in this wonky order with a goto to attempt to get the
+ compiler to make the common case integer-only loop pretty tight.
+ With gcc seems to be much straighter code than old scan_hex. */
+ redo:
+ if (!overflowed) {
+ if (value <= max_div_16) {
+ value = (value << 4) | ((xdigit - PL_hexdigit) & 15);
+ continue;
+ }
+ warn("Integer overflow in hexadecimal number");
+ overflowed = TRUE;
+ value_nv = (NV) value;
+ }
+ value_nv *= 16.0;
+ /* If an NV has not enough bits in its mantissa to
+ * represent a UV this summing of small low-order numbers
+ * is a waste of time (because the NV cannot preserve
+ * the low-order bits anyway): we could just remember when
+ * did we overflow and in the end just multiply value_nv by the
+ * right amount of 16-tuples. */
+ value_nv += (NV)((xdigit - PL_hexdigit) & 15);
+ continue;
+ }
+ if (*s == '_' && len && allow_underscores && s[1]
+ && (xdigit = strchr((char *) PL_hexdigit, s[1])))
+ {
+ --len;
+ ++s;
+ goto redo;
+ }
+ if (!(*flags & PERL_SCAN_SILENT_ILLDIGIT))
+ warn("Illegal hexadecimal digit '%c' ignored", *s);
+ break;
+ }
+
+ if ( ( overflowed && value_nv > 4294967295.0)
+#if UVSIZE > 4
+ || (!overflowed && value > 0xffffffff )
+#endif
+ ) {
+ warn("Hexadecimal number > 0xffffffff non-portable");
+ }
+ *len_p = s - start;
+ if (!overflowed) {
+ *flags = 0;
+ return value;
+ }
+ *flags = PERL_SCAN_GREATER_THAN_UV_MAX;
+ if (result)
+ *result = value_nv;
+ return UV_MAX;
+}
+#endif
+#endif
+
+#ifndef grok_oct
+#if defined(NEED_grok_oct)
+static UV DPPP_(my_grok_oct)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result);
+static
+#else
+extern UV DPPP_(my_grok_oct)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result);
+#endif
+
+#ifdef grok_oct
+# undef grok_oct
+#endif
+#define grok_oct(a,b,c,d) DPPP_(my_grok_oct)(aTHX_ a,b,c,d)
+#define Perl_grok_oct DPPP_(my_grok_oct)
+
+#if defined(NEED_grok_oct) || defined(NEED_grok_oct_GLOBAL)
+UV
+DPPP_(my_grok_oct)(pTHX_ const char *start, STRLEN *len_p, I32 *flags, NV *result)
+{
+ const char *s = start;
+ STRLEN len = *len_p;
+ UV value = 0;
+ NV value_nv = 0;
+
+ const UV max_div_8 = UV_MAX / 8;
+ bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES;
+ bool overflowed = FALSE;
+
+ for (; len-- && *s; s++) {
+ /* gcc 2.95 optimiser not smart enough to figure that this subtraction
+ out front allows slicker code. */
+ int digit = *s - '0';
+ if (digit >= 0 && digit <= 7) {
+ /* Write it in this wonky order with a goto to attempt to get the
+ compiler to make the common case integer-only loop pretty tight.
+ */
+ redo:
+ if (!overflowed) {
+ if (value <= max_div_8) {
+ value = (value << 3) | digit;
+ continue;
+ }
+ /* Bah. We're just overflowed. */
+ warn("Integer overflow in octal number");
+ overflowed = TRUE;
+ value_nv = (NV) value;
+ }
+ value_nv *= 8.0;
+ /* If an NV has not enough bits in its mantissa to
+ * represent a UV this summing of small low-order numbers
+ * is a waste of time (because the NV cannot preserve
+ * the low-order bits anyway): we could just remember when
+ * did we overflow and in the end just multiply value_nv by the
+ * right amount of 8-tuples. */
+ value_nv += (NV)digit;
+ continue;
+ }
+ if (digit == ('_' - '0') && len && allow_underscores
+ && (digit = s[1] - '0') && (digit >= 0 && digit <= 7))
+ {
+ --len;
+ ++s;
+ goto redo;
+ }
+ /* Allow \octal to work the DWIM way (that is, stop scanning
+ * as soon as non-octal characters are seen, complain only iff
+ * someone seems to want to use the digits eight and nine). */
+ if (digit == 8 || digit == 9) {
+ if (!(*flags & PERL_SCAN_SILENT_ILLDIGIT))
+ warn("Illegal octal digit '%c' ignored", *s);
+ }
+ break;
+ }
+
+ if ( ( overflowed && value_nv > 4294967295.0)
+#if UVSIZE > 4
+ || (!overflowed && value > 0xffffffff )
+#endif
+ ) {
+ warn("Octal number > 037777777777 non-portable");
+ }
+ *len_p = s - start;
+ if (!overflowed) {
+ *flags = 0;
+ return value;
+ }
+ *flags = PERL_SCAN_GREATER_THAN_UV_MAX;
+ if (result)
+ *result = value_nv;
+ return UV_MAX;
+}
+#endif
+#endif
+
+#if !defined(my_snprintf)
+#if defined(NEED_my_snprintf)
+static int DPPP_(my_my_snprintf)(char * buffer, const Size_t len, const char * format, ...);
+static
+#else
+extern int DPPP_(my_my_snprintf)(char * buffer, const Size_t len, const char * format, ...);
+#endif
+
+#define my_snprintf DPPP_(my_my_snprintf)
+#define Perl_my_snprintf DPPP_(my_my_snprintf)
+
+#if defined(NEED_my_snprintf) || defined(NEED_my_snprintf_GLOBAL)
+
+int
+DPPP_(my_my_snprintf)(char *buffer, const Size_t len, const char *format, ...)
+{
+ dTHX;
+ int retval;
+ va_list ap;
+ va_start(ap, format);
+#ifdef HAS_VSNPRINTF
+ retval = vsnprintf(buffer, len, format, ap);
+#else
+ retval = vsprintf(buffer, format, ap);
+#endif
+ va_end(ap);
+ if (retval >= (int)len)
+ Perl_croak(aTHX_ "panic: my_snprintf buffer overflow");
+ return retval;
+}
+
+#endif
+#endif
+
+#ifdef NO_XSLOCKS
+# ifdef dJMPENV
+# define dXCPT dJMPENV; int rEtV = 0
+# define XCPT_TRY_START JMPENV_PUSH(rEtV); if (rEtV == 0)
+# define XCPT_TRY_END JMPENV_POP;
+# define XCPT_CATCH if (rEtV != 0)
+# define XCPT_RETHROW JMPENV_JUMP(rEtV)
+# else
+# define dXCPT Sigjmp_buf oldTOP; int rEtV = 0
+# define XCPT_TRY_START Copy(top_env, oldTOP, 1, Sigjmp_buf); rEtV = Sigsetjmp(top_env, 1); if (rEtV == 0)
+# define XCPT_TRY_END Copy(oldTOP, top_env, 1, Sigjmp_buf);
+# define XCPT_CATCH if (rEtV != 0)
+# define XCPT_RETHROW Siglongjmp(top_env, rEtV)
+# endif
+#endif
+
+#if !defined(my_strlcat)
+#if defined(NEED_my_strlcat)
+static Size_t DPPP_(my_my_strlcat)(char * dst, const char * src, Size_t size);
+static
+#else
+extern Size_t DPPP_(my_my_strlcat)(char * dst, const char * src, Size_t size);
+#endif
+
+#define my_strlcat DPPP_(my_my_strlcat)
+#define Perl_my_strlcat DPPP_(my_my_strlcat)
+
+#if defined(NEED_my_strlcat) || defined(NEED_my_strlcat_GLOBAL)
+
+Size_t
+DPPP_(my_my_strlcat)(char *dst, const char *src, Size_t size)
+{
+ Size_t used, length, copy;
+
+ used = strlen(dst);
+ length = strlen(src);
+ if (size > 0 && used < size - 1) {
+ copy = (length >= size - used) ? size - used - 1 : length;
+ memcpy(dst + used, src, copy);
+ dst[used + copy] = '\0';
+ }
+ return used + length;
+}
+#endif
+#endif
+
+#if !defined(my_strlcpy)
+#if defined(NEED_my_strlcpy)
+static Size_t DPPP_(my_my_strlcpy)(char * dst, const char * src, Size_t size);
+static
+#else
+extern Size_t DPPP_(my_my_strlcpy)(char * dst, const char * src, Size_t size);
+#endif
+
+#define my_strlcpy DPPP_(my_my_strlcpy)
+#define Perl_my_strlcpy DPPP_(my_my_strlcpy)
+
+#if defined(NEED_my_strlcpy) || defined(NEED_my_strlcpy_GLOBAL)
+
+Size_t
+DPPP_(my_my_strlcpy)(char *dst, const char *src, Size_t size)
+{
+ Size_t length, copy;
+
+ length = strlen(src);
+ if (size > 0) {
+ copy = (length >= size) ? size - 1 : length;
+ memcpy(dst, src, copy);
+ dst[copy] = '\0';
+ }
+ return length;
+}
+
+#endif
+#endif
+
+#endif /* _P_P_PORTABILITY_H_ */
+
+/* End of File ppport.h */
diff --git a/plugin/handler_socket/perl-Net-HandlerSocket/t/HandlerSocket.t b/plugin/handler_socket/perl-Net-HandlerSocket/t/HandlerSocket.t
new file mode 100644
index 00000000..adb7c981
--- /dev/null
+++ b/plugin/handler_socket/perl-Net-HandlerSocket/t/HandlerSocket.t
@@ -0,0 +1,15 @@
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl HandlerSocket.t'
+
+#########################
+
+# change 'tests => 1' to 'tests => last_test_to_print';
+
+use Test::More tests => 1;
+BEGIN { use_ok('Net::HandlerSocket') };
+
+#########################
+
+# Insert your test code below, the Test::More module is use()ed here so read
+# its man page ( perldoc Test::More ) for help writing this test script.
+
diff --git a/plugin/handler_socket/regtest/common/binary_my.cnf b/plugin/handler_socket/regtest/common/binary_my.cnf
new file mode 100644
index 00000000..c3f7c02c
--- /dev/null
+++ b/plugin/handler_socket/regtest/common/binary_my.cnf
@@ -0,0 +1,4 @@
+
+[perl]
+default-character-set-name = binary
+
diff --git a/plugin/handler_socket/regtest/common/compat.sh b/plugin/handler_socket/regtest/common/compat.sh
new file mode 100644
index 00000000..7804bdf1
--- /dev/null
+++ b/plugin/handler_socket/regtest/common/compat.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+if [ "`uname -o`" = "Cygwin" ]; then
+ export DIFF='diff --ignore-space --strip-trailing-cr'
+elif [ "`uname`" = "Darwin" ]; then
+ export DIFF='diff'
+else
+ export DIFF='diff --ignore-space --strip-trailing-cr'
+fi
+
+compile_c() {
+ if [ "`uname -o`" = "Cygwin" ]; then
+ cl /W3 /I../.. /EHsc /FD /MD "$1" /link /DLL "/OUT:$2.dll" \
+ ../../libase.lib 2> cl.log
+ else
+ $CXX -I../.. -O3 -g -Wall -fPIC -shared "$1" -o "$2.so"
+ fi
+}
+
+compile_j() {
+ if [ "`uname -o`" = "Cygwin" ]; then
+ jdk="`echo /cygdrive/c/Program\ Files/Java/jdk* | head -1`"
+ else
+ jdk="$SUNJDK"
+ fi
+ "$jdk/bin/javac" -g "$1"/*.java
+ "$jdk/bin/jar" -cf "$1.jar" "$1"/*.class
+}
+
diff --git a/plugin/handler_socket/regtest/common/hstest.pm b/plugin/handler_socket/regtest/common/hstest.pm
new file mode 100644
index 00000000..89f273c9
--- /dev/null
+++ b/plugin/handler_socket/regtest/common/hstest.pm
@@ -0,0 +1,66 @@
+
+# vim:sw=2:ai
+
+package hstest;
+
+use DBI;
+use Net::HandlerSocket;
+
+our %conf = ();
+
+sub get_conf_env {
+ my ($key, $defval) = @_;
+ return $ENV{$key} || $defval;
+}
+
+sub init_conf {
+ $conf{host} = get_conf_env("MYHOST", "localhost");
+ $conf{myport} = get_conf_env("MYPORT", 3306);
+ $conf{dbname} = get_conf_env("MYDBNAME", "hstestdb");
+ $conf{ssps} = get_conf_env("MYSSPS");
+ $conf{user} = get_conf_env("MYSQLUSER", "root");
+ $conf{pass} = get_conf_env("MYSQLPASS", "");
+ $conf{hsport} = get_conf_env("HSPORT", 9998);
+ $conf{hspass} = get_conf_env("HSPASS", undef);
+}
+
+sub get_dbi_connection {
+ my ($dbname, $host, $myport, $ssps, $user, $pass)
+ = ($conf{dbname}, $conf{host}, $conf{myport}, $conf{ssps},
+ $conf{user}, $conf{pass});
+ my $mycnf = "binary_my.cnf";
+ my $dsn = "DBI:MariaDB:database=;host=$host;port=$myport"
+ . ";mariadb_server_prepare=$ssps"
+ . ";mariadb_read_default_group=perl"
+ . ";mariadb_read_default_file=../common/$mycnf";
+ my $dbh = DBI->connect($dsn, $user, $pass, { RaiseError => 1 });
+ return $dbh;
+}
+
+sub init_testdb {
+ my $charset = $_[0] || "binary";
+ my $dbh = get_dbi_connection();
+ my $dbname = $conf{dbname};
+ $dbh->do("drop database if exists $dbname");
+ $dbh->do("create database $dbname default character set $charset");
+ $dbh->do("use $dbname");
+ return $dbh;
+}
+
+sub get_hs_connection {
+ my ($host, $port) = @_;
+ $host ||= $conf{host};
+ $port ||= $conf{hsport};
+ my $hsargs = { 'host' => $host, 'port' => $port };
+ my $conn = new Net::HandlerSocket($hsargs);
+ if (defined($conn) && defined($conf{hspass})) {
+ $conn->auth($conf{hspass});
+ }
+ return $conn;
+}
+
+
+init_conf();
+
+1;
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/run.sh b/plugin/handler_socket/regtest/test_01_lib/run.sh
new file mode 100755
index 00000000..84603d65
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/run.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+TESTS="01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24";
+
+source ../common/compat.sh
+
+for i in $TESTS; do
+ perl "test$i.pl" > test$i.log 2> test$i.log2
+done
+for i in $TESTS; do
+ if ! $DIFF -u test$i.log test$i.expected; then
+ echo "test$i failed";
+ exit 1
+ fi
+ if [ -f "test$i.expect2" ]; then
+ lines="`wc -l < test$i.expect2`"
+ head -$lines test$i.log2 > test$i.log2h
+ if ! $DIFF -u test$i.log2h test$i.expect2 && \
+ ! $DIFF -u test$i.log2h test$i.expect2ef; then
+ echo "test$i failed";
+ exit 1
+ fi
+ fi
+done
+echo "OK."
+exit 0
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test01.expected b/plugin/handler_socket/regtest/test_01_lib/test01.expected
new file mode 100644
index 00000000..37da3242
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test01.expected
@@ -0,0 +1,100 @@
+k0 v1020
+k1 v6351
+k10 v70410
+k11 v75111
+k12 v36712
+k13 v40013
+k14 v39714
+k15 v17015
+k16 v71916
+k17 v73417
+k18 v58718
+k19 v49419
+k2 v8032
+k20 v52320
+k21 v95421
+k22 v43322
+k23 v82023
+k24 v28324
+k25 v83725
+k26 v20526
+k27 v41527
+k28 v54528
+k29 v58329
+k3 v9253
+k30 v5230
+k31 v32331
+k32 v61432
+k33 v67933
+k34 v80534
+k35 v45135
+k36 v11536
+k37 v26937
+k38 v21838
+k39 v61739
+k4 v7754
+k40 v87840
+k41 v34541
+k42 v51242
+k43 v96943
+k44 v40844
+k45 v29145
+k46 v85846
+k47 v95347
+k48 v71048
+k49 v14249
+k5 v5375
+k50 v68250
+k51 v93451
+k52 v62152
+k53 v96553
+k54 v57454
+k55 v20455
+k56 v29856
+k57 v13457
+k58 v98358
+k59 v44459
+k6 v5926
+k60 v14460
+k61 v15261
+k62 v18762
+k63 v21563
+k64 v864
+k65 v69765
+k66 v65166
+k67 v28067
+k68 v70168
+k69 v53769
+k7 v4147
+k70 v41370
+k71 v6971
+k72 v8672
+k73 v82273
+k74 v67074
+k75 v37075
+k76 v80676
+k77 v68877
+k78 v2678
+k79 v6679
+k8 v5908
+k80 v80280
+k81 v17181
+k82 v55782
+k83 v84783
+k84 v77784
+k85 v73085
+k86 v98786
+k87 v11587
+k88 v64688
+k89 v49689
+k9 v3029
+k90 v12090
+k91 v68491
+k92 v37492
+k93 v6593
+k94 v37094
+k95 v17495
+k96 v82896
+k97 v86797
+k98 v75998
+k99 v70399
diff --git a/plugin/handler_socket/regtest/test_01_lib/test01.pl b/plugin/handler_socket/regtest/test_01_lib/test01.pl
new file mode 100644
index 00000000..0a3ad9e9
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test01.pl
@@ -0,0 +1,38 @@
+#!/usr/bin/env perl
+
+# vim:sw=2:ai
+
+# test for libmysql
+
+BEGIN {
+ push @INC, "../common/";
+};
+
+use strict;
+use warnings;
+use hstest;
+
+my $dbh = hstest::init_testdb();
+my $table = 'hstesttbl';
+my $tablesize = 100;
+$dbh->do(
+ "create table $table (k varchar(30) primary key, v varchar(30) not null) " .
+ "engine = innodb");
+srand(999);
+
+my %valmap = ();
+
+my $sth = $dbh->prepare("insert into $table values (?,?)");
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = "k" . $i;
+ my $v = "v" . int(rand(1000)) . $i;
+ $sth->execute($k, $v);
+ $valmap{$k} = $v;
+}
+
+my $aref = $dbh->selectall_arrayref("select k,v from $table order by k");
+for my $row (@$aref) {
+ my ($k, $v) = @$row;
+ print "$k $v\n";
+}
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test02.expected b/plugin/handler_socket/regtest/test_01_lib/test02.expected
new file mode 100644
index 00000000..37da3242
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test02.expected
@@ -0,0 +1,100 @@
+k0 v1020
+k1 v6351
+k10 v70410
+k11 v75111
+k12 v36712
+k13 v40013
+k14 v39714
+k15 v17015
+k16 v71916
+k17 v73417
+k18 v58718
+k19 v49419
+k2 v8032
+k20 v52320
+k21 v95421
+k22 v43322
+k23 v82023
+k24 v28324
+k25 v83725
+k26 v20526
+k27 v41527
+k28 v54528
+k29 v58329
+k3 v9253
+k30 v5230
+k31 v32331
+k32 v61432
+k33 v67933
+k34 v80534
+k35 v45135
+k36 v11536
+k37 v26937
+k38 v21838
+k39 v61739
+k4 v7754
+k40 v87840
+k41 v34541
+k42 v51242
+k43 v96943
+k44 v40844
+k45 v29145
+k46 v85846
+k47 v95347
+k48 v71048
+k49 v14249
+k5 v5375
+k50 v68250
+k51 v93451
+k52 v62152
+k53 v96553
+k54 v57454
+k55 v20455
+k56 v29856
+k57 v13457
+k58 v98358
+k59 v44459
+k6 v5926
+k60 v14460
+k61 v15261
+k62 v18762
+k63 v21563
+k64 v864
+k65 v69765
+k66 v65166
+k67 v28067
+k68 v70168
+k69 v53769
+k7 v4147
+k70 v41370
+k71 v6971
+k72 v8672
+k73 v82273
+k74 v67074
+k75 v37075
+k76 v80676
+k77 v68877
+k78 v2678
+k79 v6679
+k8 v5908
+k80 v80280
+k81 v17181
+k82 v55782
+k83 v84783
+k84 v77784
+k85 v73085
+k86 v98786
+k87 v11587
+k88 v64688
+k89 v49689
+k9 v3029
+k90 v12090
+k91 v68491
+k92 v37492
+k93 v6593
+k94 v37094
+k95 v17495
+k96 v82896
+k97 v86797
+k98 v75998
+k99 v70399
diff --git a/plugin/handler_socket/regtest/test_01_lib/test02.pl b/plugin/handler_socket/regtest/test_01_lib/test02.pl
new file mode 100644
index 00000000..f9bdc8b6
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test02.pl
@@ -0,0 +1,49 @@
+#!/usr/bin/env perl
+
+# vim:sw=2:ai
+
+# test for '>='
+
+BEGIN {
+ push @INC, "../common/";
+};
+
+use strict;
+use warnings;
+use hstest;
+
+my $dbh = hstest::init_testdb();
+my $table = 'hstesttbl';
+my $tablesize = 100;
+$dbh->do(
+ "create table $table (k varchar(30) primary key, v varchar(30) not null) " .
+ "engine = innodb");
+srand(999);
+
+my %valmap = ();
+
+my $sth = $dbh->prepare("insert into $table values (?,?)");
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = "k" . $i;
+ my $v = "v" . int(rand(1000)) . $i;
+ $sth->execute($k, $v);
+ $valmap{$k} = $v;
+}
+
+my $hs = hstest::get_hs_connection();
+my $dbname = $hstest::conf{dbname};
+$hs->open_index(1, $dbname, $table, '', 'k,v');
+my $r = $hs->execute_single(1, '>=', [ '' ], 10000, 0);
+shift(@$r);
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = $r->[$i * 2];
+ my $v = $r->[$i * 2 + 1];
+ print "$k $v\n";
+}
+
+my $aref = $dbh->selectall_arrayref("select k,v from $table order by k");
+for my $row (@$aref) {
+ my ($k, $v) = @$row;
+ #print "$k $v\n";
+}
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test03.expected b/plugin/handler_socket/regtest/test_01_lib/test03.expected
new file mode 100644
index 00000000..87b90cd0
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test03.expected
@@ -0,0 +1,771 @@
+WR
+0 0
+1 1
+2 2
+3 3
+4 4
+5 5
+6 6
+7 7
+8 8
+9 9
+10 10
+11 11
+12 12
+13 13
+14 14
+15 15
+16 16
+17 17
+18 18
+19 19
+20 20
+21 21
+22 22
+23 23
+24 24
+25 25
+26 26
+27 27
+28 28
+29 29
+30 30
+31 31
+32 32
+33 33
+34 34
+35 35
+36 36
+37 37
+38 38
+39 39
+40 40
+41 41
+42 42
+43 43
+44 44
+45 45
+46 46
+47 47
+48 48
+49 49
+50 50
+51 51
+52 52
+53 53
+54 54
+55 55
+56 56
+57 57
+58 58
+59 59
+60 60
+61 61
+62 62
+63 63
+64 64
+65 65
+66 66
+67 67
+68 68
+69 69
+70 70
+71 71
+72 72
+73 73
+74 74
+75 75
+76 76
+77 77
+78 78
+79 79
+80 80
+81 81
+82 82
+83 83
+84 84
+85 85
+86 86
+87 87
+88 88
+89 89
+90 90
+91 91
+92 92
+93 93
+94 94
+95 95
+96 96
+97 97
+98 98
+99 99
+100 100
+101 101
+102 102
+103 103
+104 104
+105 105
+106 106
+107 107
+108 108
+109 109
+110 110
+111 111
+112 112
+113 113
+114 114
+115 115
+116 116
+117 117
+118 118
+119 119
+120 120
+121 121
+122 122
+123 123
+124 124
+125 125
+126 126
+127 127
+128 128
+129 129
+130 130
+131 131
+132 132
+133 133
+134 134
+135 135
+136 136
+137 137
+138 138
+139 139
+140 140
+141 141
+142 142
+143 143
+144 144
+145 145
+146 146
+147 147
+148 148
+149 149
+150 150
+151 151
+152 152
+153 153
+154 154
+155 155
+156 156
+157 157
+158 158
+159 159
+160 160
+161 161
+162 162
+163 163
+164 164
+165 165
+166 166
+167 167
+168 168
+169 169
+170 170
+171 171
+172 172
+173 173
+174 174
+175 175
+176 176
+177 177
+178 178
+179 179
+180 180
+181 181
+182 182
+183 183
+184 184
+185 185
+186 186
+187 187
+188 188
+189 189
+190 190
+191 191
+192 192
+193 193
+194 194
+195 195
+196 196
+197 197
+198 198
+199 199
+200 200
+201 201
+202 202
+203 203
+204 204
+205 205
+206 206
+207 207
+208 208
+209 209
+210 210
+211 211
+212 212
+213 213
+214 214
+215 215
+216 216
+217 217
+218 218
+219 219
+220 220
+221 221
+222 222
+223 223
+224 224
+225 225
+226 226
+227 227
+228 228
+229 229
+230 230
+231 231
+232 232
+233 233
+234 234
+235 235
+236 236
+237 237
+238 238
+239 239
+240 240
+241 241
+242 242
+243 243
+244 244
+245 245
+246 246
+247 247
+248 248
+249 249
+250 250
+251 251
+252 252
+253 253
+254 254
+255 255
+HS
+0 0
+1 1
+10 10
+100 100
+101 101
+102 102
+103 103
+104 104
+105 105
+106 106
+107 107
+108 108
+109 109
+11 11
+110 110
+111 111
+112 112
+113 113
+114 114
+115 115
+116 116
+117 117
+118 118
+119 119
+12 12
+120 120
+121 121
+122 122
+123 123
+124 124
+125 125
+126 126
+127 127
+128 128
+129 129
+13 13
+130 130
+131 131
+132 132
+133 133
+134 134
+135 135
+136 136
+137 137
+138 138
+139 139
+14 14
+140 140
+141 141
+142 142
+143 143
+144 144
+145 145
+146 146
+147 147
+148 148
+149 149
+15 15
+150 150
+151 151
+152 152
+153 153
+154 154
+155 155
+156 156
+157 157
+158 158
+159 159
+16 16
+160 160
+161 161
+162 162
+163 163
+164 164
+165 165
+166 166
+167 167
+168 168
+169 169
+17 17
+170 170
+171 171
+172 172
+173 173
+174 174
+175 175
+176 176
+177 177
+178 178
+179 179
+18 18
+180 180
+181 181
+182 182
+183 183
+184 184
+185 185
+186 186
+187 187
+188 188
+189 189
+19 19
+190 190
+191 191
+192 192
+193 193
+194 194
+195 195
+196 196
+197 197
+198 198
+199 199
+2 2
+20 20
+200 200
+201 201
+202 202
+203 203
+204 204
+205 205
+206 206
+207 207
+208 208
+209 209
+21 21
+210 210
+211 211
+212 212
+213 213
+214 214
+215 215
+216 216
+217 217
+218 218
+219 219
+22 22
+220 220
+221 221
+222 222
+223 223
+224 224
+225 225
+226 226
+227 227
+228 228
+229 229
+23 23
+230 230
+231 231
+232 232
+233 233
+234 234
+235 235
+236 236
+237 237
+238 238
+239 239
+24 24
+240 240
+241 241
+242 242
+243 243
+244 244
+245 245
+246 246
+247 247
+248 248
+249 249
+25 25
+250 250
+251 251
+252 252
+253 253
+254 254
+255 255
+26 26
+27 27
+28 28
+29 29
+3 3
+30 30
+31 31
+32 32
+33 33
+34 34
+35 35
+36 36
+37 37
+38 38
+39 39
+4 4
+40 40
+41 41
+42 42
+43 43
+44 44
+45 45
+46 46
+47 47
+48 48
+49 49
+5 5
+50 50
+51 51
+52 52
+53 53
+54 54
+55 55
+56 56
+57 57
+58 58
+59 59
+6 6
+60 60
+61 61
+62 62
+63 63
+64 64
+65 65
+66 66
+67 67
+68 68
+69 69
+7 7
+70 70
+71 71
+72 72
+73 73
+74 74
+75 75
+76 76
+77 77
+78 78
+79 79
+8 8
+80 80
+81 81
+82 82
+83 83
+84 84
+85 85
+86 86
+87 87
+88 88
+89 89
+9 9
+90 90
+91 91
+92 92
+93 93
+94 94
+95 95
+96 96
+97 97
+98 98
+99 99
+MY
+0 0
+1 1
+10 10
+100 100
+101 101
+102 102
+103 103
+104 104
+105 105
+106 106
+107 107
+108 108
+109 109
+11 11
+110 110
+111 111
+112 112
+113 113
+114 114
+115 115
+116 116
+117 117
+118 118
+119 119
+12 12
+120 120
+121 121
+122 122
+123 123
+124 124
+125 125
+126 126
+127 127
+128 128
+129 129
+13 13
+130 130
+131 131
+132 132
+133 133
+134 134
+135 135
+136 136
+137 137
+138 138
+139 139
+14 14
+140 140
+141 141
+142 142
+143 143
+144 144
+145 145
+146 146
+147 147
+148 148
+149 149
+15 15
+150 150
+151 151
+152 152
+153 153
+154 154
+155 155
+156 156
+157 157
+158 158
+159 159
+16 16
+160 160
+161 161
+162 162
+163 163
+164 164
+165 165
+166 166
+167 167
+168 168
+169 169
+17 17
+170 170
+171 171
+172 172
+173 173
+174 174
+175 175
+176 176
+177 177
+178 178
+179 179
+18 18
+180 180
+181 181
+182 182
+183 183
+184 184
+185 185
+186 186
+187 187
+188 188
+189 189
+19 19
+190 190
+191 191
+192 192
+193 193
+194 194
+195 195
+196 196
+197 197
+198 198
+199 199
+2 2
+20 20
+200 200
+201 201
+202 202
+203 203
+204 204
+205 205
+206 206
+207 207
+208 208
+209 209
+21 21
+210 210
+211 211
+212 212
+213 213
+214 214
+215 215
+216 216
+217 217
+218 218
+219 219
+22 22
+220 220
+221 221
+222 222
+223 223
+224 224
+225 225
+226 226
+227 227
+228 228
+229 229
+23 23
+230 230
+231 231
+232 232
+233 233
+234 234
+235 235
+236 236
+237 237
+238 238
+239 239
+24 24
+240 240
+241 241
+242 242
+243 243
+244 244
+245 245
+246 246
+247 247
+248 248
+249 249
+25 25
+250 250
+251 251
+252 252
+253 253
+254 254
+255 255
+26 26
+27 27
+28 28
+29 29
+3 3
+30 30
+31 31
+32 32
+33 33
+34 34
+35 35
+36 36
+37 37
+38 38
+39 39
+4 4
+40 40
+41 41
+42 42
+43 43
+44 44
+45 45
+46 46
+47 47
+48 48
+49 49
+5 5
+50 50
+51 51
+52 52
+53 53
+54 54
+55 55
+56 56
+57 57
+58 58
+59 59
+6 6
+60 60
+61 61
+62 62
+63 63
+64 64
+65 65
+66 66
+67 67
+68 68
+69 69
+7 7
+70 70
+71 71
+72 72
+73 73
+74 74
+75 75
+76 76
+77 77
+78 78
+79 79
+8 8
+80 80
+81 81
+82 82
+83 83
+84 84
+85 85
+86 86
+87 87
+88 88
+89 89
+9 9
+90 90
+91 91
+92 92
+93 93
+94 94
+95 95
+96 96
+97 97
+98 98
+99 99
diff --git a/plugin/handler_socket/regtest/test_01_lib/test03.pl b/plugin/handler_socket/regtest/test_01_lib/test03.pl
new file mode 100644
index 00000000..a51aaf3b
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test03.pl
@@ -0,0 +1,61 @@
+#!/usr/bin/env perl
+
+# vim:sw=2:ai
+
+# test for binary cleanness (#1)
+
+BEGIN {
+ push @INC, "../common/";
+};
+
+use strict;
+use warnings;
+use hstest;
+
+my $dbh = hstest::init_testdb();
+my $table = 'hstesttbl';
+my $tablesize = 256;
+$dbh->do(
+ "create table $table (k varchar(30) primary key, v varchar(30) not null) " .
+ "engine = innodb default charset = binary");
+srand(999);
+
+my %valmap = ();
+
+print "WR\n";
+my $sth = $dbh->prepare("insert into $table values (?,?)");
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = "" . $i;
+ my $v = pack("C", $i);
+ my $vnum = unpack("C", $v);
+ print "$k $vnum\n";
+ $sth->execute($k, $v);
+ $valmap{$k} = $v;
+}
+
+my $hs = hstest::get_hs_connection();
+my $dbname = $hstest::conf{dbname};
+$hs->open_index(1, $dbname, $table, '', 'k,v');
+my $r = $hs->execute_single(1, '>=', [ '' ], 10000, 0);
+shift(@$r);
+print "HS\n";
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = $r->[$i * 2];
+ my $v = $r->[$i * 2 + 1];
+ my $vnum = unpack("C", $v);
+ print "$k $vnum\n";
+ print "MISMATCH\n" if ($k ne $vnum);
+ print "LEN\n" if (length($v) != 1);
+}
+undef $hs;
+
+print "MY\n";
+my $aref = $dbh->selectall_arrayref("select k,v from $table order by k");
+for my $row (@$aref) {
+ my ($k, $v) = @$row;
+ my $vnum = unpack("C", $v);
+ print "$k $vnum\n";
+ print "MISMATCH\n" if ($k ne $vnum);
+ print "LEN\n" if (length($v) != 1);
+}
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test04.expected b/plugin/handler_socket/regtest/test_01_lib/test04.expected
new file mode 100644
index 00000000..ceeac438
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test04.expected
Binary files differ
diff --git a/plugin/handler_socket/regtest/test_01_lib/test04.pl b/plugin/handler_socket/regtest/test_01_lib/test04.pl
new file mode 100644
index 00000000..d922b713
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test04.pl
@@ -0,0 +1,63 @@
+#!/usr/bin/env perl
+
+# vim:sw=2:ai
+
+# test for binary cleanness (#2)
+
+BEGIN {
+ push @INC, "../common/";
+};
+
+use strict;
+use warnings;
+use hstest;
+
+my $dbh = hstest::init_testdb();
+my $table = 'hstesttbl';
+my $tablesize = 256;
+$dbh->do(
+ "create table $table (k varchar(30) primary key, v varchar(30) not null) " .
+ "engine = innodb default charset = binary");
+srand(999);
+
+my %valmap = ();
+
+print "WR\n";
+my $sth = $dbh->prepare("insert into $table values (?,?)");
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = "" . $i;
+ my $v = pack("C", $i);
+ my $vnum = unpack("C", $v);
+ print "$k $vnum\n";
+ $sth->execute($k, "a" . $v . "a");
+ $valmap{$k} = $v;
+}
+
+my $hs = hstest::get_hs_connection();
+my $dbname = $hstest::conf{dbname};
+$hs->open_index(1, $dbname, $table, '', 'k,v');
+my $r = $hs->execute_single(1, '>=', [ '' ], 10000, 0);
+shift(@$r);
+print "HS\n";
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = $r->[$i * 2];
+ my $v = $r->[$i * 2 + 1];
+ my $len = length($v);
+ my $vnum = unpack("C", substr($v, 1, 1));
+ print "$k $vnum $len [$v]\n";
+ print "MISMATCH\n" if ($k ne $vnum);
+ print "LEN\n" if $len != 3;
+}
+undef $hs;
+
+print "MY\n";
+my $aref = $dbh->selectall_arrayref("select k,v from $table order by k");
+for my $row (@$aref) {
+ my ($k, $v) = @$row;
+ my $len = length($v);
+ my $vnum = unpack("C", substr($v, 1, 1));
+ print "$k $vnum $len [$v]\n";
+ print "MISMATCH\n" if ($k ne $vnum);
+ print "LEN\n" if $len != 3;
+}
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test05.expected b/plugin/handler_socket/regtest/test_01_lib/test05.expected
new file mode 100644
index 00000000..6a86a446
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test05.expected
@@ -0,0 +1,771 @@
+WR
+0 [null]
+1 1
+2 [null]
+3 3
+4 [null]
+5 5
+6 [null]
+7 7
+8 [null]
+9 9
+10 [null]
+11 11
+12 [null]
+13 13
+14 [null]
+15 15
+16 [null]
+17 17
+18 [null]
+19 19
+20 [null]
+21 21
+22 [null]
+23 23
+24 [null]
+25 25
+26 [null]
+27 27
+28 [null]
+29 29
+30 [null]
+31 31
+32 [null]
+33 33
+34 [null]
+35 35
+36 [null]
+37 37
+38 [null]
+39 39
+40 [null]
+41 41
+42 [null]
+43 43
+44 [null]
+45 45
+46 [null]
+47 47
+48 [null]
+49 49
+50 [null]
+51 51
+52 [null]
+53 53
+54 [null]
+55 55
+56 [null]
+57 57
+58 [null]
+59 59
+60 [null]
+61 61
+62 [null]
+63 63
+64 [null]
+65 65
+66 [null]
+67 67
+68 [null]
+69 69
+70 [null]
+71 71
+72 [null]
+73 73
+74 [null]
+75 75
+76 [null]
+77 77
+78 [null]
+79 79
+80 [null]
+81 81
+82 [null]
+83 83
+84 [null]
+85 85
+86 [null]
+87 87
+88 [null]
+89 89
+90 [null]
+91 91
+92 [null]
+93 93
+94 [null]
+95 95
+96 [null]
+97 97
+98 [null]
+99 99
+100 [null]
+101 101
+102 [null]
+103 103
+104 [null]
+105 105
+106 [null]
+107 107
+108 [null]
+109 109
+110 [null]
+111 111
+112 [null]
+113 113
+114 [null]
+115 115
+116 [null]
+117 117
+118 [null]
+119 119
+120 [null]
+121 121
+122 [null]
+123 123
+124 [null]
+125 125
+126 [null]
+127 127
+128 [null]
+129 129
+130 [null]
+131 131
+132 [null]
+133 133
+134 [null]
+135 135
+136 [null]
+137 137
+138 [null]
+139 139
+140 [null]
+141 141
+142 [null]
+143 143
+144 [null]
+145 145
+146 [null]
+147 147
+148 [null]
+149 149
+150 [null]
+151 151
+152 [null]
+153 153
+154 [null]
+155 155
+156 [null]
+157 157
+158 [null]
+159 159
+160 [null]
+161 161
+162 [null]
+163 163
+164 [null]
+165 165
+166 [null]
+167 167
+168 [null]
+169 169
+170 [null]
+171 171
+172 [null]
+173 173
+174 [null]
+175 175
+176 [null]
+177 177
+178 [null]
+179 179
+180 [null]
+181 181
+182 [null]
+183 183
+184 [null]
+185 185
+186 [null]
+187 187
+188 [null]
+189 189
+190 [null]
+191 191
+192 [null]
+193 193
+194 [null]
+195 195
+196 [null]
+197 197
+198 [null]
+199 199
+200 [null]
+201 201
+202 [null]
+203 203
+204 [null]
+205 205
+206 [null]
+207 207
+208 [null]
+209 209
+210 [null]
+211 211
+212 [null]
+213 213
+214 [null]
+215 215
+216 [null]
+217 217
+218 [null]
+219 219
+220 [null]
+221 221
+222 [null]
+223 223
+224 [null]
+225 225
+226 [null]
+227 227
+228 [null]
+229 229
+230 [null]
+231 231
+232 [null]
+233 233
+234 [null]
+235 235
+236 [null]
+237 237
+238 [null]
+239 239
+240 [null]
+241 241
+242 [null]
+243 243
+244 [null]
+245 245
+246 [null]
+247 247
+248 [null]
+249 249
+250 [null]
+251 251
+252 [null]
+253 253
+254 [null]
+255 255
+HS
+0 [null]
+1 1
+10 [null]
+100 [null]
+101 101
+102 [null]
+103 103
+104 [null]
+105 105
+106 [null]
+107 107
+108 [null]
+109 109
+11 11
+110 [null]
+111 111
+112 [null]
+113 113
+114 [null]
+115 115
+116 [null]
+117 117
+118 [null]
+119 119
+12 [null]
+120 [null]
+121 121
+122 [null]
+123 123
+124 [null]
+125 125
+126 [null]
+127 127
+128 [null]
+129 129
+13 13
+130 [null]
+131 131
+132 [null]
+133 133
+134 [null]
+135 135
+136 [null]
+137 137
+138 [null]
+139 139
+14 [null]
+140 [null]
+141 141
+142 [null]
+143 143
+144 [null]
+145 145
+146 [null]
+147 147
+148 [null]
+149 149
+15 15
+150 [null]
+151 151
+152 [null]
+153 153
+154 [null]
+155 155
+156 [null]
+157 157
+158 [null]
+159 159
+16 [null]
+160 [null]
+161 161
+162 [null]
+163 163
+164 [null]
+165 165
+166 [null]
+167 167
+168 [null]
+169 169
+17 17
+170 [null]
+171 171
+172 [null]
+173 173
+174 [null]
+175 175
+176 [null]
+177 177
+178 [null]
+179 179
+18 [null]
+180 [null]
+181 181
+182 [null]
+183 183
+184 [null]
+185 185
+186 [null]
+187 187
+188 [null]
+189 189
+19 19
+190 [null]
+191 191
+192 [null]
+193 193
+194 [null]
+195 195
+196 [null]
+197 197
+198 [null]
+199 199
+2 [null]
+20 [null]
+200 [null]
+201 201
+202 [null]
+203 203
+204 [null]
+205 205
+206 [null]
+207 207
+208 [null]
+209 209
+21 21
+210 [null]
+211 211
+212 [null]
+213 213
+214 [null]
+215 215
+216 [null]
+217 217
+218 [null]
+219 219
+22 [null]
+220 [null]
+221 221
+222 [null]
+223 223
+224 [null]
+225 225
+226 [null]
+227 227
+228 [null]
+229 229
+23 23
+230 [null]
+231 231
+232 [null]
+233 233
+234 [null]
+235 235
+236 [null]
+237 237
+238 [null]
+239 239
+24 [null]
+240 [null]
+241 241
+242 [null]
+243 243
+244 [null]
+245 245
+246 [null]
+247 247
+248 [null]
+249 249
+25 25
+250 [null]
+251 251
+252 [null]
+253 253
+254 [null]
+255 255
+26 [null]
+27 27
+28 [null]
+29 29
+3 3
+30 [null]
+31 31
+32 [null]
+33 33
+34 [null]
+35 35
+36 [null]
+37 37
+38 [null]
+39 39
+4 [null]
+40 [null]
+41 41
+42 [null]
+43 43
+44 [null]
+45 45
+46 [null]
+47 47
+48 [null]
+49 49
+5 5
+50 [null]
+51 51
+52 [null]
+53 53
+54 [null]
+55 55
+56 [null]
+57 57
+58 [null]
+59 59
+6 [null]
+60 [null]
+61 61
+62 [null]
+63 63
+64 [null]
+65 65
+66 [null]
+67 67
+68 [null]
+69 69
+7 7
+70 [null]
+71 71
+72 [null]
+73 73
+74 [null]
+75 75
+76 [null]
+77 77
+78 [null]
+79 79
+8 [null]
+80 [null]
+81 81
+82 [null]
+83 83
+84 [null]
+85 85
+86 [null]
+87 87
+88 [null]
+89 89
+9 9
+90 [null]
+91 91
+92 [null]
+93 93
+94 [null]
+95 95
+96 [null]
+97 97
+98 [null]
+99 99
+MY
+0 [null]
+1 1
+10 [null]
+100 [null]
+101 101
+102 [null]
+103 103
+104 [null]
+105 105
+106 [null]
+107 107
+108 [null]
+109 109
+11 11
+110 [null]
+111 111
+112 [null]
+113 113
+114 [null]
+115 115
+116 [null]
+117 117
+118 [null]
+119 119
+12 [null]
+120 [null]
+121 121
+122 [null]
+123 123
+124 [null]
+125 125
+126 [null]
+127 127
+128 [null]
+129 129
+13 13
+130 [null]
+131 131
+132 [null]
+133 133
+134 [null]
+135 135
+136 [null]
+137 137
+138 [null]
+139 139
+14 [null]
+140 [null]
+141 141
+142 [null]
+143 143
+144 [null]
+145 145
+146 [null]
+147 147
+148 [null]
+149 149
+15 15
+150 [null]
+151 151
+152 [null]
+153 153
+154 [null]
+155 155
+156 [null]
+157 157
+158 [null]
+159 159
+16 [null]
+160 [null]
+161 161
+162 [null]
+163 163
+164 [null]
+165 165
+166 [null]
+167 167
+168 [null]
+169 169
+17 17
+170 [null]
+171 171
+172 [null]
+173 173
+174 [null]
+175 175
+176 [null]
+177 177
+178 [null]
+179 179
+18 [null]
+180 [null]
+181 181
+182 [null]
+183 183
+184 [null]
+185 185
+186 [null]
+187 187
+188 [null]
+189 189
+19 19
+190 [null]
+191 191
+192 [null]
+193 193
+194 [null]
+195 195
+196 [null]
+197 197
+198 [null]
+199 199
+2 [null]
+20 [null]
+200 [null]
+201 201
+202 [null]
+203 203
+204 [null]
+205 205
+206 [null]
+207 207
+208 [null]
+209 209
+21 21
+210 [null]
+211 211
+212 [null]
+213 213
+214 [null]
+215 215
+216 [null]
+217 217
+218 [null]
+219 219
+22 [null]
+220 [null]
+221 221
+222 [null]
+223 223
+224 [null]
+225 225
+226 [null]
+227 227
+228 [null]
+229 229
+23 23
+230 [null]
+231 231
+232 [null]
+233 233
+234 [null]
+235 235
+236 [null]
+237 237
+238 [null]
+239 239
+24 [null]
+240 [null]
+241 241
+242 [null]
+243 243
+244 [null]
+245 245
+246 [null]
+247 247
+248 [null]
+249 249
+25 25
+250 [null]
+251 251
+252 [null]
+253 253
+254 [null]
+255 255
+26 [null]
+27 27
+28 [null]
+29 29
+3 3
+30 [null]
+31 31
+32 [null]
+33 33
+34 [null]
+35 35
+36 [null]
+37 37
+38 [null]
+39 39
+4 [null]
+40 [null]
+41 41
+42 [null]
+43 43
+44 [null]
+45 45
+46 [null]
+47 47
+48 [null]
+49 49
+5 5
+50 [null]
+51 51
+52 [null]
+53 53
+54 [null]
+55 55
+56 [null]
+57 57
+58 [null]
+59 59
+6 [null]
+60 [null]
+61 61
+62 [null]
+63 63
+64 [null]
+65 65
+66 [null]
+67 67
+68 [null]
+69 69
+7 7
+70 [null]
+71 71
+72 [null]
+73 73
+74 [null]
+75 75
+76 [null]
+77 77
+78 [null]
+79 79
+8 [null]
+80 [null]
+81 81
+82 [null]
+83 83
+84 [null]
+85 85
+86 [null]
+87 87
+88 [null]
+89 89
+9 9
+90 [null]
+91 91
+92 [null]
+93 93
+94 [null]
+95 95
+96 [null]
+97 97
+98 [null]
+99 99
diff --git a/plugin/handler_socket/regtest/test_01_lib/test05.pl b/plugin/handler_socket/regtest/test_01_lib/test05.pl
new file mode 100644
index 00000000..2993e7a9
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test05.pl
@@ -0,0 +1,59 @@
+#!/usr/bin/env perl
+
+# vim:sw=2:ai
+
+# test for binary cleanness (#3)
+
+BEGIN {
+ push @INC, "../common/";
+};
+
+use strict;
+use warnings;
+use hstest;
+
+my $dbh = hstest::init_testdb();
+my $table = 'hstesttbl';
+my $tablesize = 256;
+$dbh->do(
+ "create table $table (k varchar(30) primary key, v varchar(30)) " .
+ "engine = innodb default charset = binary");
+srand(999);
+
+my %valmap = ();
+
+print "WR\n";
+my $sth = $dbh->prepare("insert into $table values (?,?)");
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = "" . $i;
+ my $v = ($i % 2 == 1) ? $i : undef;
+ $sth->execute($k, $v);
+ $v = "[null]" if !defined($v);
+ print "$k $v\n";
+ $valmap{$k} = $v;
+}
+
+my $hs = hstest::get_hs_connection();
+my $dbname = $hstest::conf{dbname};
+$hs->open_index(1, $dbname, $table, '', 'k,v');
+my $r = $hs->execute_single(1, '>=', [ '' ], 10000, 0);
+shift(@$r);
+print "HS\n";
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = $r->[$i * 2];
+ my $v = $r->[$i * 2 + 1];
+ $v = "[null]" if !defined($v);
+ print "$k $v\n";
+ print "MISMATCH\n" if ($valmap{$k} ne $v);
+}
+undef $hs;
+
+print "MY\n";
+my $aref = $dbh->selectall_arrayref("select k,v from $table order by k");
+for my $row (@$aref) {
+ my ($k, $v) = @$row;
+ $v = "[null]" if !defined($v);
+ print "$k $v\n";
+ print "MISMATCH\n" if ($valmap{$k} ne $v);
+}
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test06.expected b/plugin/handler_socket/regtest/test_01_lib/test06.expected
new file mode 100644
index 00000000..b376c4af
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test06.expected
@@ -0,0 +1,644 @@
+HSINSERTDUMP_TABLE
+0 v1_0 v2_0
+1 v1_1 v2_1
+10 v1_10 v2_10
+100 v1_100 v2_100
+101 v1_101 v2_101
+102 v1_102 v2_102
+103 v1_103 v2_103
+104 v1_104 v2_104
+105 v1_105 v2_105
+106 v1_106 v2_106
+107 v1_107 v2_107
+108 v1_108 v2_108
+109 v1_109 v2_109
+11 v1_11 v2_11
+110 v1_110 v2_110
+111 v1_111 v2_111
+112 v1_112 v2_112
+113 v1_113 v2_113
+114 v1_114 v2_114
+115 v1_115 v2_115
+116 v1_116 v2_116
+117 v1_117 v2_117
+118 v1_118 v2_118
+119 v1_119 v2_119
+12 v1_12 v2_12
+120 v1_120 v2_120
+121 v1_121 v2_121
+122 v1_122 v2_122
+123 v1_123 v2_123
+124 v1_124 v2_124
+125 v1_125 v2_125
+126 v1_126 v2_126
+127 v1_127 v2_127
+128 v1_128 v2_128
+129 v1_129 v2_129
+13 v1_13 v2_13
+130 v1_130 v2_130
+131 v1_131 v2_131
+132 v1_132 v2_132
+133 v1_133 v2_133
+134 v1_134 v2_134
+135 v1_135 v2_135
+136 v1_136 v2_136
+137 v1_137 v2_137
+138 v1_138 v2_138
+139 v1_139 v2_139
+14 v1_14 v2_14
+140 v1_140 v2_140
+141 v1_141 v2_141
+142 v1_142 v2_142
+143 v1_143 v2_143
+144 v1_144 v2_144
+145 v1_145 v2_145
+146 v1_146 v2_146
+147 v1_147 v2_147
+148 v1_148 v2_148
+149 v1_149 v2_149
+15 v1_15 v2_15
+150 v1_150 v2_150
+151 v1_151 v2_151
+152 v1_152 v2_152
+153 v1_153 v2_153
+154 v1_154 v2_154
+155 v1_155 v2_155
+156 v1_156 v2_156
+157 v1_157 v2_157
+158 v1_158 v2_158
+159 v1_159 v2_159
+16 v1_16 v2_16
+160 v1_160 v2_160
+161 v1_161 v2_161
+162 v1_162 v2_162
+163 v1_163 v2_163
+164 v1_164 v2_164
+165 v1_165 v2_165
+166 v1_166 v2_166
+167 v1_167 v2_167
+168 v1_168 v2_168
+169 v1_169 v2_169
+17 v1_17 v2_17
+170 v1_170 v2_170
+171 v1_171 v2_171
+172 v1_172 v2_172
+173 v1_173 v2_173
+174 v1_174 v2_174
+175 v1_175 v2_175
+176 v1_176 v2_176
+177 v1_177 v2_177
+178 v1_178 v2_178
+179 v1_179 v2_179
+18 v1_18 v2_18
+180 v1_180 v2_180
+181 v1_181 v2_181
+182 v1_182 v2_182
+183 v1_183 v2_183
+184 v1_184 v2_184
+185 v1_185 v2_185
+186 v1_186 v2_186
+187 v1_187 v2_187
+188 v1_188 v2_188
+189 v1_189 v2_189
+19 v1_19 v2_19
+190 v1_190 v2_190
+191 v1_191 v2_191
+192 v1_192 v2_192
+193 v1_193 v2_193
+194 v1_194 v2_194
+195 v1_195 v2_195
+196 v1_196 v2_196
+197 v1_197 v2_197
+198 v1_198 v2_198
+199 v1_199 v2_199
+2 v1_2 v2_2
+20 v1_20 v2_20
+200 v1_200 v2_200
+201 v1_201 v2_201
+202 v1_202 v2_202
+203 v1_203 v2_203
+204 v1_204 v2_204
+205 v1_205 v2_205
+206 v1_206 v2_206
+207 v1_207 v2_207
+208 v1_208 v2_208
+209 v1_209 v2_209
+21 v1_21 v2_21
+210 v1_210 v2_210
+211 v1_211 v2_211
+212 v1_212 v2_212
+213 v1_213 v2_213
+214 v1_214 v2_214
+215 v1_215 v2_215
+216 v1_216 v2_216
+217 v1_217 v2_217
+218 v1_218 v2_218
+219 v1_219 v2_219
+22 v1_22 v2_22
+220 v1_220 v2_220
+221 v1_221 v2_221
+222 v1_222 v2_222
+223 v1_223 v2_223
+224 v1_224 v2_224
+225 v1_225 v2_225
+226 v1_226 v2_226
+227 v1_227 v2_227
+228 v1_228 v2_228
+229 v1_229 v2_229
+23 v1_23 v2_23
+230 v1_230 v2_230
+231 v1_231 v2_231
+232 v1_232 v2_232
+233 v1_233 v2_233
+234 v1_234 v2_234
+235 v1_235 v2_235
+236 v1_236 v2_236
+237 v1_237 v2_237
+238 v1_238 v2_238
+239 v1_239 v2_239
+24 v1_24 v2_24
+240 v1_240 v2_240
+241 v1_241 v2_241
+242 v1_242 v2_242
+243 v1_243 v2_243
+244 v1_244 v2_244
+245 v1_245 v2_245
+246 v1_246 v2_246
+247 v1_247 v2_247
+248 v1_248 v2_248
+249 v1_249 v2_249
+25 v1_25 v2_25
+250 v1_250 v2_250
+251 v1_251 v2_251
+252 v1_252 v2_252
+253 v1_253 v2_253
+254 v1_254 v2_254
+255 v1_255 v2_255
+26 v1_26 v2_26
+27 v1_27 v2_27
+28 v1_28 v2_28
+29 v1_29 v2_29
+3 v1_3 v2_3
+30 v1_30 v2_30
+31 v1_31 v2_31
+32 v1_32 v2_32
+33 v1_33 v2_33
+34 v1_34 v2_34
+35 v1_35 v2_35
+36 v1_36 v2_36
+37 v1_37 v2_37
+38 v1_38 v2_38
+39 v1_39 v2_39
+4 v1_4 v2_4
+40 v1_40 v2_40
+41 v1_41 v2_41
+42 v1_42 v2_42
+43 v1_43 v2_43
+44 v1_44 v2_44
+45 v1_45 v2_45
+46 v1_46 v2_46
+47 v1_47 v2_47
+48 v1_48 v2_48
+49 v1_49 v2_49
+5 v1_5 v2_5
+50 v1_50 v2_50
+51 v1_51 v2_51
+52 v1_52 v2_52
+53 v1_53 v2_53
+54 v1_54 v2_54
+55 v1_55 v2_55
+56 v1_56 v2_56
+57 v1_57 v2_57
+58 v1_58 v2_58
+59 v1_59 v2_59
+6 v1_6 v2_6
+60 v1_60 v2_60
+61 v1_61 v2_61
+62 v1_62 v2_62
+63 v1_63 v2_63
+64 v1_64 v2_64
+65 v1_65 v2_65
+66 v1_66 v2_66
+67 v1_67 v2_67
+68 v1_68 v2_68
+69 v1_69 v2_69
+7 v1_7 v2_7
+70 v1_70 v2_70
+71 v1_71 v2_71
+72 v1_72 v2_72
+73 v1_73 v2_73
+74 v1_74 v2_74
+75 v1_75 v2_75
+76 v1_76 v2_76
+77 v1_77 v2_77
+78 v1_78 v2_78
+79 v1_79 v2_79
+8 v1_8 v2_8
+80 v1_80 v2_80
+81 v1_81 v2_81
+82 v1_82 v2_82
+83 v1_83 v2_83
+84 v1_84 v2_84
+85 v1_85 v2_85
+86 v1_86 v2_86
+87 v1_87 v2_87
+88 v1_88 v2_88
+89 v1_89 v2_89
+9 v1_9 v2_9
+90 v1_90 v2_90
+91 v1_91 v2_91
+92 v1_92 v2_92
+93 v1_93 v2_93
+94 v1_94 v2_94
+95 v1_95 v2_95
+96 v1_96 v2_96
+97 v1_97 v2_97
+98 v1_98 v2_98
+99 v1_99 v2_99
+HSUPDATEDUMP_TABLE
+0 mod_0 v2_0
+1 mod_1 v2_1
+10 mod_10 v2_10
+100 mod_100 v2_100
+101 mod_101 v2_101
+102 mod_102 v2_102
+103 mod_103 v2_103
+104 mod_104 v2_104
+105 mod_105 v2_105
+106 mod_106 v2_106
+107 mod_107 v2_107
+108 mod_108 v2_108
+109 mod_109 v2_109
+11 mod_11 v2_11
+110 mod_110 v2_110
+111 mod_111 v2_111
+112 mod_112 v2_112
+113 mod_113 v2_113
+114 mod_114 v2_114
+115 mod_115 v2_115
+116 mod_116 v2_116
+117 mod_117 v2_117
+118 mod_118 v2_118
+119 mod_119 v2_119
+12 mod_12 v2_12
+120 mod_120 v2_120
+121 mod_121 v2_121
+122 mod_122 v2_122
+123 mod_123 v2_123
+124 mod_124 v2_124
+125 mod_125 v2_125
+126 mod_126 v2_126
+127 mod_127 v2_127
+128 mod_128 v2_128
+129 mod_129 v2_129
+13 mod_13 v2_13
+130 mod_130 v2_130
+131 mod_131 v2_131
+132 mod_132 v2_132
+133 mod_133 v2_133
+134 mod_134 v2_134
+135 mod_135 v2_135
+136 mod_136 v2_136
+137 mod_137 v2_137
+138 mod_138 v2_138
+139 mod_139 v2_139
+14 mod_14 v2_14
+140 mod_140 v2_140
+141 mod_141 v2_141
+142 mod_142 v2_142
+143 mod_143 v2_143
+144 mod_144 v2_144
+145 mod_145 v2_145
+146 mod_146 v2_146
+147 mod_147 v2_147
+148 mod_148 v2_148
+149 mod_149 v2_149
+15 mod_15 v2_15
+150 mod_150 v2_150
+151 mod_151 v2_151
+152 mod_152 v2_152
+153 mod_153 v2_153
+154 mod_154 v2_154
+155 mod_155 v2_155
+156 mod_156 v2_156
+157 mod_157 v2_157
+158 mod_158 v2_158
+159 mod_159 v2_159
+16 mod_16 v2_16
+160 mod_160 v2_160
+161 mod_161 v2_161
+162 mod_162 v2_162
+163 mod_163 v2_163
+164 mod_164 v2_164
+165 mod_165 v2_165
+166 mod_166 v2_166
+167 mod_167 v2_167
+168 mod_168 v2_168
+169 mod_169 v2_169
+17 mod_17 v2_17
+170 mod_170 v2_170
+171 mod_171 v2_171
+172 mod_172 v2_172
+173 mod_173 v2_173
+174 mod_174 v2_174
+175 mod_175 v2_175
+176 mod_176 v2_176
+177 mod_177 v2_177
+178 mod_178 v2_178
+179 mod_179 v2_179
+18 mod_18 v2_18
+180 mod_180 v2_180
+181 mod_181 v2_181
+182 mod_182 v2_182
+183 mod_183 v2_183
+184 mod_184 v2_184
+185 mod_185 v2_185
+186 mod_186 v2_186
+187 mod_187 v2_187
+188 mod_188 v2_188
+189 mod_189 v2_189
+19 mod_19 v2_19
+190 mod_190 v2_190
+191 mod_191 v2_191
+192 mod_192 v2_192
+193 mod_193 v2_193
+194 mod_194 v2_194
+195 mod_195 v2_195
+196 mod_196 v2_196
+197 mod_197 v2_197
+198 mod_198 v2_198
+199 mod_199 v2_199
+2 mod_2 v2_2
+20 mod_20 v2_20
+200 mod_200 v2_200
+201 mod_201 v2_201
+202 mod_202 v2_202
+203 mod_203 v2_203
+204 mod_204 v2_204
+205 mod_205 v2_205
+206 mod_206 v2_206
+207 mod_207 v2_207
+208 mod_208 v2_208
+209 mod_209 v2_209
+21 mod_21 v2_21
+210 mod_210 v2_210
+211 mod_211 v2_211
+212 mod_212 v2_212
+213 mod_213 v2_213
+214 mod_214 v2_214
+215 mod_215 v2_215
+216 mod_216 v2_216
+217 mod_217 v2_217
+218 mod_218 v2_218
+219 mod_219 v2_219
+22 mod_22 v2_22
+220 mod_220 v2_220
+221 mod_221 v2_221
+222 mod_222 v2_222
+223 mod_223 v2_223
+224 mod_224 v2_224
+225 mod_225 v2_225
+226 mod_226 v2_226
+227 mod_227 v2_227
+228 mod_228 v2_228
+229 mod_229 v2_229
+23 mod_23 v2_23
+230 mod_230 v2_230
+231 mod_231 v2_231
+232 mod_232 v2_232
+233 mod_233 v2_233
+234 mod_234 v2_234
+235 mod_235 v2_235
+236 mod_236 v2_236
+237 mod_237 v2_237
+238 mod_238 v2_238
+239 mod_239 v2_239
+24 mod_24 v2_24
+240 mod_240 v2_240
+241 mod_241 v2_241
+242 mod_242 v2_242
+243 mod_243 v2_243
+244 mod_244 v2_244
+245 mod_245 v2_245
+246 mod_246 v2_246
+247 mod_247 v2_247
+248 mod_248 v2_248
+249 mod_249 v2_249
+25 mod_25 v2_25
+250 mod_250 v2_250
+251 mod_251 v2_251
+252 mod_252 v2_252
+253 mod_253 v2_253
+254 mod_254 v2_254
+255 mod_255 v2_255
+26 mod_26 v2_26
+27 mod_27 v2_27
+28 mod_28 v2_28
+29 mod_29 v2_29
+3 mod_3 v2_3
+30 mod_30 v2_30
+31 mod_31 v2_31
+32 mod_32 v2_32
+33 mod_33 v2_33
+34 mod_34 v2_34
+35 mod_35 v2_35
+36 mod_36 v2_36
+37 mod_37 v2_37
+38 mod_38 v2_38
+39 mod_39 v2_39
+4 mod_4 v2_4
+40 mod_40 v2_40
+41 mod_41 v2_41
+42 mod_42 v2_42
+43 mod_43 v2_43
+44 mod_44 v2_44
+45 mod_45 v2_45
+46 mod_46 v2_46
+47 mod_47 v2_47
+48 mod_48 v2_48
+49 mod_49 v2_49
+5 mod_5 v2_5
+50 mod_50 v2_50
+51 mod_51 v2_51
+52 mod_52 v2_52
+53 mod_53 v2_53
+54 mod_54 v2_54
+55 mod_55 v2_55
+56 mod_56 v2_56
+57 mod_57 v2_57
+58 mod_58 v2_58
+59 mod_59 v2_59
+6 mod_6 v2_6
+60 mod_60 v2_60
+61 mod_61 v2_61
+62 mod_62 v2_62
+63 mod_63 v2_63
+64 mod_64 v2_64
+65 mod_65 v2_65
+66 mod_66 v2_66
+67 mod_67 v2_67
+68 mod_68 v2_68
+69 mod_69 v2_69
+7 mod_7 v2_7
+70 mod_70 v2_70
+71 mod_71 v2_71
+72 mod_72 v2_72
+73 mod_73 v2_73
+74 mod_74 v2_74
+75 mod_75 v2_75
+76 mod_76 v2_76
+77 mod_77 v2_77
+78 mod_78 v2_78
+79 mod_79 v2_79
+8 mod_8 v2_8
+80 mod_80 v2_80
+81 mod_81 v2_81
+82 mod_82 v2_82
+83 mod_83 v2_83
+84 mod_84 v2_84
+85 mod_85 v2_85
+86 mod_86 v2_86
+87 mod_87 v2_87
+88 mod_88 v2_88
+89 mod_89 v2_89
+9 mod_9 v2_9
+90 mod_90 v2_90
+91 mod_91 v2_91
+92 mod_92 v2_92
+93 mod_93 v2_93
+94 mod_94 v2_94
+95 mod_95 v2_95
+96 mod_96 v2_96
+97 mod_97 v2_97
+98 mod_98 v2_98
+99 mod_99 v2_99
+HSDELETE
+DUMP_TABLE
+1 mod_1 v2_1
+101 mod_101 v2_101
+103 mod_103 v2_103
+105 mod_105 v2_105
+107 mod_107 v2_107
+109 mod_109 v2_109
+11 mod_11 v2_11
+111 mod_111 v2_111
+113 mod_113 v2_113
+115 mod_115 v2_115
+117 mod_117 v2_117
+119 mod_119 v2_119
+121 mod_121 v2_121
+123 mod_123 v2_123
+125 mod_125 v2_125
+127 mod_127 v2_127
+129 mod_129 v2_129
+13 mod_13 v2_13
+131 mod_131 v2_131
+133 mod_133 v2_133
+135 mod_135 v2_135
+137 mod_137 v2_137
+139 mod_139 v2_139
+141 mod_141 v2_141
+143 mod_143 v2_143
+145 mod_145 v2_145
+147 mod_147 v2_147
+149 mod_149 v2_149
+15 mod_15 v2_15
+151 mod_151 v2_151
+153 mod_153 v2_153
+155 mod_155 v2_155
+157 mod_157 v2_157
+159 mod_159 v2_159
+161 mod_161 v2_161
+163 mod_163 v2_163
+165 mod_165 v2_165
+167 mod_167 v2_167
+169 mod_169 v2_169
+17 mod_17 v2_17
+171 mod_171 v2_171
+173 mod_173 v2_173
+175 mod_175 v2_175
+177 mod_177 v2_177
+179 mod_179 v2_179
+181 mod_181 v2_181
+183 mod_183 v2_183
+185 mod_185 v2_185
+187 mod_187 v2_187
+189 mod_189 v2_189
+19 mod_19 v2_19
+191 mod_191 v2_191
+193 mod_193 v2_193
+195 mod_195 v2_195
+197 mod_197 v2_197
+199 mod_199 v2_199
+201 mod_201 v2_201
+203 mod_203 v2_203
+205 mod_205 v2_205
+207 mod_207 v2_207
+209 mod_209 v2_209
+21 mod_21 v2_21
+211 mod_211 v2_211
+213 mod_213 v2_213
+215 mod_215 v2_215
+217 mod_217 v2_217
+219 mod_219 v2_219
+221 mod_221 v2_221
+223 mod_223 v2_223
+225 mod_225 v2_225
+227 mod_227 v2_227
+229 mod_229 v2_229
+23 mod_23 v2_23
+231 mod_231 v2_231
+233 mod_233 v2_233
+235 mod_235 v2_235
+237 mod_237 v2_237
+239 mod_239 v2_239
+241 mod_241 v2_241
+243 mod_243 v2_243
+245 mod_245 v2_245
+247 mod_247 v2_247
+249 mod_249 v2_249
+25 mod_25 v2_25
+251 mod_251 v2_251
+253 mod_253 v2_253
+255 mod_255 v2_255
+27 mod_27 v2_27
+29 mod_29 v2_29
+3 mod_3 v2_3
+31 mod_31 v2_31
+33 mod_33 v2_33
+35 mod_35 v2_35
+37 mod_37 v2_37
+39 mod_39 v2_39
+41 mod_41 v2_41
+43 mod_43 v2_43
+45 mod_45 v2_45
+47 mod_47 v2_47
+49 mod_49 v2_49
+5 mod_5 v2_5
+51 mod_51 v2_51
+53 mod_53 v2_53
+55 mod_55 v2_55
+57 mod_57 v2_57
+59 mod_59 v2_59
+61 mod_61 v2_61
+63 mod_63 v2_63
+65 mod_65 v2_65
+67 mod_67 v2_67
+69 mod_69 v2_69
+7 mod_7 v2_7
+71 mod_71 v2_71
+73 mod_73 v2_73
+75 mod_75 v2_75
+77 mod_77 v2_77
+79 mod_79 v2_79
+81 mod_81 v2_81
+83 mod_83 v2_83
+85 mod_85 v2_85
+87 mod_87 v2_87
+89 mod_89 v2_89
+9 mod_9 v2_9
+91 mod_91 v2_91
+93 mod_93 v2_93
+95 mod_95 v2_95
+97 mod_97 v2_97
+99 mod_99 v2_99
diff --git a/plugin/handler_socket/regtest/test_01_lib/test06.pl b/plugin/handler_socket/regtest/test_01_lib/test06.pl
new file mode 100644
index 00000000..69dd107e
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test06.pl
@@ -0,0 +1,90 @@
+#!/usr/bin/env perl
+
+# vim:sw=2:ai
+
+# test for insert/update/delete
+
+BEGIN {
+ push @INC, "../common/";
+};
+
+use strict;
+use warnings;
+use hstest;
+
+my $dbh = hstest::init_testdb();
+my $table = 'hstesttbl';
+my $tablesize = 256;
+$dbh->do(
+ "create table $table (" .
+ "k varchar(30) primary key, " .
+ "v1 varchar(30), " .
+ "v2 varchar(30)) " .
+ "engine = innodb default charset = binary");
+srand(999);
+
+my %valmap = ();
+
+print "HSINSERT";
+my $hs = hstest::get_hs_connection(undef, 9999);
+my $dbname = $hstest::conf{dbname};
+$hs->open_index(1, $dbname, $table, '', 'k,v1,v2');
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = "" . $i;
+ my $v1 = "v1_" . $i;
+ my $v2 = "v2_" . $i;
+ my $r = $hs->execute_insert(1, [ $k, $v1, $v2 ]);
+ my $err = $r->[0];
+ if ($err != 0) {
+ my $err_str = $r->[1];
+ print "$err $err_str\n";
+ }
+}
+undef $hs;
+
+dump_table();
+
+print "HSUPDATE";
+$hs = hstest::get_hs_connection(undef, 9999);
+$dbname = $hstest::conf{dbname};
+$hs->open_index(2, $dbname, $table, '', 'v1');
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $r = $hs->execute_single(2, '=', [ $i ], 1000, 0, 'U', [ "mod_$i" ]);
+ my $err = $r->[0];
+ if ($err != 0) {
+ my $err_str = $r->[1];
+ print "$err $err_str\n";
+ }
+}
+undef $hs;
+
+dump_table();
+
+print "HSDELETE\n";
+$hs = hstest::get_hs_connection(undef, 9999);
+$dbname = $hstest::conf{dbname};
+$hs->open_index(3, $dbname, $table, '', '');
+for (my $i = 0; $i < $tablesize; $i = $i + 2) {
+ my $r = $hs->execute_single(3, '=', [ $i ], 1000, 0, 'D');
+ my $err = $r->[0];
+ if ($err != 0) {
+ my $err_str = $r->[1];
+ print "$err $err_str\n";
+ }
+}
+undef $hs;
+
+dump_table();
+
+sub dump_table {
+ print "DUMP_TABLE\n";
+ my $aref = $dbh->selectall_arrayref("select k,v1,v2 from $table order by k");
+ for my $row (@$aref) {
+ my ($k, $v1, $v2) = @$row;
+ $v1 = "[null]" if !defined($v1);
+ $v2 = "[null]" if !defined($v2);
+ print "$k $v1 $v2\n";
+ # print "MISMATCH\n" if ($valmap{$k} ne $v);
+ }
+}
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test07.expected b/plugin/handler_socket/regtest/test_01_lib/test07.expected
new file mode 100644
index 00000000..f2047c2e
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test07.expected
@@ -0,0 +1,304 @@
+MY
+0 1v1020 2v6350
+1 1v8031 2v9251
+2 1v7752 2v5372
+3 [NULL] 2v4143
+4 1v5904 2v3024
+5 1v7045 2v7515
+6 1v3676 2v4006
+7 1v3977 2v1707
+8 1v7198 2v7348
+9 1v5879 2v4949
+10 1v52310 2v95410
+11 1v43311 2v82011
+12 1v28312 2v83712
+13 [NULL] 2v41513
+14 1v54514 2v58314
+15 1v5215 2v32315
+16 1v61416 2v67916
+17 1v80517 2v45117
+18 1v11518 2v26918
+19 1v21819 2v61719
+20 1v87820 2v34520
+21 1v51221 2v96921
+22 1v40822 2v29122
+23 [NULL] 2v95323
+24 1v71024 2v14224
+25 1v68225 2v93425
+26 1v62126 2v96526
+27 1v57427 2v20427
+28 1v29828 2v13428
+29 1v98329 2v44429
+30 1v14430 2v15230
+31 1v18731 2v21531
+32 1v832 2v69732
+33 [NULL] 2v28033
+34 1v70134 2v53734
+35 1v41335 2v6935
+36 1v8636 2v82236
+37 1v67037 2v37037
+38 1v80638 2v68838
+39 1v2639 2v6639
+40 1v80240 2v17140
+41 1v55741 2v84741
+42 1v77742 2v73042
+43 [NULL] 2v11543
+44 1v64644 2v49644
+45 1v12045 2v68445
+46 1v37446 2v6546
+47 1v37047 2v17447
+48 1v82848 2v86748
+49 1v75949 2v70349
+50 1v84350 2v94250
+51 1v40151 2v36251
+52 1v36752 2v30752
+53 [NULL] 2v16753
+54 1v79954 2v82954
+55 1v53955 2v37955
+56 1v56056 2v85856
+57 1v57957 2v2657
+58 1v88758 2v50758
+59 1v34559 2v89859
+60 1v43060 2v80160
+61 1v84561 2v32561
+62 1v62462 2v48062
+63 [NULL] 2v67663
+64 1v5364 2v73664
+65 1v80965 2v27065
+66 1v17566 2v83966
+67 1v6167 2v22267
+68 1v35868 2v50568
+69 1v62769 2v90669
+70 1v4670 2v98170
+71 1v11971 2v471
+72 1v1472 2v48072
+73 [NULL] 2v40573
+74 1v87574 2v63974
+75 1v82775 2v34475
+76 1v59876 2v56376
+77 1v77077 2v51677
+78 1v53878 2v54878
+79 1v35779 2v32279
+80 1v3680 2v37080
+81 1v33181 2v81581
+82 1v76982 2v66882
+83 [NULL] 2v28183
+84 1v69684 2v45284
+85 1v40685 2v185
+86 1v39586 2v32486
+87 1v3687 2v73887
+88 1v16088 2v7988
+89 1v75989 2v65789
+90 1v3190 2v78390
+91 1v65091 2v82491
+92 1v85292 2v6892
+93 [NULL] 2v54693
+94 1v81394 2v77594
+95 1v8795 2v69695
+96 1v19696 2v38096
+97 1v7997 2v75197
+98 1v32398 2v21798
+99 1v3799 2v70199
+HS
+0 1v1020 2v6350
+1 1v8031 2v9251
+2 1v7752 2v5372
+3 [NULL] 2v4143
+4 1v5904 2v3024
+5 1v7045 2v7515
+6 1v3676 2v4006
+7 1v3977 2v1707
+8 1v7198 2v7348
+9 1v5879 2v4949
+10 1v52310 2v95410
+11 1v43311 2v82011
+12 1v28312 2v83712
+13 [NULL] 2v41513
+14 1v54514 2v58314
+15 1v5215 2v32315
+16 1v61416 2v67916
+17 1v80517 2v45117
+18 1v11518 2v26918
+19 1v21819 2v61719
+20 1v87820 2v34520
+21 1v51221 2v96921
+22 1v40822 2v29122
+23 [NULL] 2v95323
+24 1v71024 2v14224
+25 1v68225 2v93425
+26 1v62126 2v96526
+27 1v57427 2v20427
+28 1v29828 2v13428
+29 1v98329 2v44429
+30 1v14430 2v15230
+31 1v18731 2v21531
+32 1v832 2v69732
+33 [NULL] 2v28033
+34 1v70134 2v53734
+35 1v41335 2v6935
+36 1v8636 2v82236
+37 1v67037 2v37037
+38 1v80638 2v68838
+39 1v2639 2v6639
+40 1v80240 2v17140
+41 1v55741 2v84741
+42 1v77742 2v73042
+43 [NULL] 2v11543
+44 1v64644 2v49644
+45 1v12045 2v68445
+46 1v37446 2v6546
+47 1v37047 2v17447
+48 1v82848 2v86748
+49 1v75949 2v70349
+50 1v84350 2v94250
+51 1v40151 2v36251
+52 1v36752 2v30752
+53 [NULL] 2v16753
+54 1v79954 2v82954
+55 1v53955 2v37955
+56 1v56056 2v85856
+57 1v57957 2v2657
+58 1v88758 2v50758
+59 1v34559 2v89859
+60 1v43060 2v80160
+61 1v84561 2v32561
+62 1v62462 2v48062
+63 [NULL] 2v67663
+64 1v5364 2v73664
+65 1v80965 2v27065
+66 1v17566 2v83966
+67 1v6167 2v22267
+68 1v35868 2v50568
+69 1v62769 2v90669
+70 1v4670 2v98170
+71 1v11971 2v471
+72 1v1472 2v48072
+73 [NULL] 2v40573
+74 1v87574 2v63974
+75 1v82775 2v34475
+76 1v59876 2v56376
+77 1v77077 2v51677
+78 1v53878 2v54878
+79 1v35779 2v32279
+80 1v3680 2v37080
+81 1v33181 2v81581
+82 1v76982 2v66882
+83 [NULL] 2v28183
+84 1v69684 2v45284
+85 1v40685 2v185
+86 1v39586 2v32486
+87 1v3687 2v73887
+88 1v16088 2v7988
+89 1v75989 2v65789
+90 1v3190 2v78390
+91 1v65091 2v82491
+92 1v85292 2v6892
+93 [NULL] 2v54693
+94 1v81394 2v77594
+95 1v8795 2v69695
+96 1v19696 2v38096
+97 1v7997 2v75197
+98 1v32398 2v21798
+99 1v3799 2v70199
+2ndIDX
+2ndidx 0 1v1020 => 0 1v1020 2v6350
+2ndidx 1 1v8031 => 1 1v8031 2v9251
+2ndidx 2 1v7752 => 2 1v7752 2v5372
+2ndidx 4 1v5904 => 4 1v5904 2v3024
+2ndidx 5 1v7045 => 5 1v7045 2v7515
+2ndidx 6 1v3676 => 6 1v3676 2v4006
+2ndidx 7 1v3977 => 7 1v3977 2v1707
+2ndidx 8 1v7198 => 8 1v7198 2v7348
+2ndidx 9 1v5879 => 9 1v5879 2v4949
+2ndidx 10 1v52310 => 10 1v52310 2v95410
+2ndidx 11 1v43311 => 11 1v43311 2v82011
+2ndidx 12 1v28312 => 12 1v28312 2v83712
+2ndidx 14 1v54514 => 14 1v54514 2v58314
+2ndidx 15 1v5215 => 15 1v5215 2v32315
+2ndidx 16 1v61416 => 16 1v61416 2v67916
+2ndidx 17 1v80517 => 17 1v80517 2v45117
+2ndidx 18 1v11518 => 18 1v11518 2v26918
+2ndidx 19 1v21819 => 19 1v21819 2v61719
+2ndidx 20 1v87820 => 20 1v87820 2v34520
+2ndidx 21 1v51221 => 21 1v51221 2v96921
+2ndidx 22 1v40822 => 22 1v40822 2v29122
+2ndidx 24 1v71024 => 24 1v71024 2v14224
+2ndidx 25 1v68225 => 25 1v68225 2v93425
+2ndidx 26 1v62126 => 26 1v62126 2v96526
+2ndidx 27 1v57427 => 27 1v57427 2v20427
+2ndidx 28 1v29828 => 28 1v29828 2v13428
+2ndidx 29 1v98329 => 29 1v98329 2v44429
+2ndidx 30 1v14430 => 30 1v14430 2v15230
+2ndidx 31 1v18731 => 31 1v18731 2v21531
+2ndidx 32 1v832 => 32 1v832 2v69732
+2ndidx 34 1v70134 => 34 1v70134 2v53734
+2ndidx 35 1v41335 => 35 1v41335 2v6935
+2ndidx 36 1v8636 => 36 1v8636 2v82236
+2ndidx 37 1v67037 => 37 1v67037 2v37037
+2ndidx 38 1v80638 => 38 1v80638 2v68838
+2ndidx 39 1v2639 => 39 1v2639 2v6639
+2ndidx 40 1v80240 => 40 1v80240 2v17140
+2ndidx 41 1v55741 => 41 1v55741 2v84741
+2ndidx 42 1v77742 => 42 1v77742 2v73042
+2ndidx 44 1v64644 => 44 1v64644 2v49644
+2ndidx 45 1v12045 => 45 1v12045 2v68445
+2ndidx 46 1v37446 => 46 1v37446 2v6546
+2ndidx 47 1v37047 => 47 1v37047 2v17447
+2ndidx 48 1v82848 => 48 1v82848 2v86748
+2ndidx 49 1v75949 => 49 1v75949 2v70349
+2ndidx 50 1v84350 => 50 1v84350 2v94250
+2ndidx 51 1v40151 => 51 1v40151 2v36251
+2ndidx 52 1v36752 => 52 1v36752 2v30752
+2ndidx 54 1v79954 => 54 1v79954 2v82954
+2ndidx 55 1v53955 => 55 1v53955 2v37955
+2ndidx 56 1v56056 => 56 1v56056 2v85856
+2ndidx 57 1v57957 => 57 1v57957 2v2657
+2ndidx 58 1v88758 => 58 1v88758 2v50758
+2ndidx 59 1v34559 => 59 1v34559 2v89859
+2ndidx 60 1v43060 => 60 1v43060 2v80160
+2ndidx 61 1v84561 => 61 1v84561 2v32561
+2ndidx 62 1v62462 => 62 1v62462 2v48062
+2ndidx 64 1v5364 => 64 1v5364 2v73664
+2ndidx 65 1v80965 => 65 1v80965 2v27065
+2ndidx 66 1v17566 => 66 1v17566 2v83966
+2ndidx 67 1v6167 => 67 1v6167 2v22267
+2ndidx 68 1v35868 => 68 1v35868 2v50568
+2ndidx 69 1v62769 => 69 1v62769 2v90669
+2ndidx 70 1v4670 => 70 1v4670 2v98170
+2ndidx 71 1v11971 => 71 1v11971 2v471
+2ndidx 72 1v1472 => 72 1v1472 2v48072
+2ndidx 74 1v87574 => 74 1v87574 2v63974
+2ndidx 75 1v82775 => 75 1v82775 2v34475
+2ndidx 76 1v59876 => 76 1v59876 2v56376
+2ndidx 77 1v77077 => 77 1v77077 2v51677
+2ndidx 78 1v53878 => 78 1v53878 2v54878
+2ndidx 79 1v35779 => 79 1v35779 2v32279
+2ndidx 80 1v3680 => 80 1v3680 2v37080
+2ndidx 81 1v33181 => 81 1v33181 2v81581
+2ndidx 82 1v76982 => 82 1v76982 2v66882
+2ndidx 84 1v69684 => 84 1v69684 2v45284
+2ndidx 85 1v40685 => 85 1v40685 2v185
+2ndidx 86 1v39586 => 86 1v39586 2v32486
+2ndidx 87 1v3687 => 87 1v3687 2v73887
+2ndidx 88 1v16088 => 88 1v16088 2v7988
+2ndidx 89 1v75989 => 89 1v75989 2v65789
+2ndidx 90 1v3190 => 90 1v3190 2v78390
+2ndidx 91 1v65091 => 91 1v65091 2v82491
+2ndidx 92 1v85292 => 92 1v85292 2v6892
+2ndidx 94 1v81394 => 94 1v81394 2v77594
+2ndidx 95 1v8795 => 95 1v8795 2v69695
+2ndidx 96 1v19696 => 96 1v19696 2v38096
+2ndidx 97 1v7997 => 97 1v7997 2v75197
+2ndidx 98 1v32398 => 98 1v32398 2v21798
+2ndidx 99 1v3799 => 99 1v3799 2v70199
+2ndIDX NULL
+2ndidxnull 3 2v4143
+2ndidxnull 13 2v41513
+2ndidxnull 23 2v95323
+2ndidxnull 33 2v28033
+2ndidxnull 43 2v11543
+2ndidxnull 53 2v16753
+2ndidxnull 63 2v67663
+2ndidxnull 73 2v40573
+2ndidxnull 83 2v28183
+2ndidxnull 93 2v54693
diff --git a/plugin/handler_socket/regtest/test_01_lib/test07.pl b/plugin/handler_socket/regtest/test_01_lib/test07.pl
new file mode 100644
index 00000000..2286aeba
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test07.pl
@@ -0,0 +1,98 @@
+#!/usr/bin/env perl
+
+# vim:sw=2:ai
+
+# test for nulls
+
+BEGIN {
+ push @INC, "../common/";
+};
+
+# use strict;
+use warnings;
+use hstest;
+
+my $dbh = hstest::init_testdb();
+my $table = 'hstesttbl';
+my $tablesize = 100;
+$dbh->do(
+ "create table $table (" .
+ "k int primary key, v1 varchar(30), v2 varchar(30), " .
+ "key idxv1 (v1) " .
+ ") engine = innodb");
+srand(999);
+
+my %valmap = ();
+
+my $sth = $dbh->prepare("insert into $table values (?,?,?)");
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = "" . $i;
+ my $v1 = "1v" . int(rand(1000)) . $i;
+ my $v2 = "2v" . int(rand(1000)) . $i;
+ if ($i % 10 == 3) {
+ $v1 = undef;
+ }
+ $sth->execute($k, $v1, $v2);
+ $valmap{$k} = $v1;
+}
+
+print "MY\n";
+my $aref = $dbh->selectall_arrayref("select k,v1,v2 from $table order by k");
+for my $row (@$aref) {
+ my ($k, $v1, $v2) = @$row;
+ $v1 = "[NULL]" if (!defined($v1));
+ print "$k $v1 $v2\n";
+}
+
+print "HS\n";
+my $hs = hstest::get_hs_connection();
+my $dbname = $hstest::conf{dbname};
+$hs->open_index(1, $dbname, $table, '', 'k,v1,v2');
+my $r = $hs->execute_single(1, '>=', [ '' ], 10000, 0);
+shift(@$r);
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = $r->[$i * 3];
+ my $v1 = $r->[$i * 3 + 1];
+ my $v2 = $r->[$i * 3 + 2];
+ $v1 = "[NULL]" if (!defined($v1));
+ print "$k $v1 $v2\n";
+}
+
+print "2ndIDX\n";
+$hs->open_index(2, $dbname, $table, 'idxv1', 'k,v1,v2');
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = "" . $i;
+ my $v1 = $valmap{$k};
+ next if !defined($v1);
+ my $r = $hs->execute_single(2, '=', [ $v1 ], 1, 0);
+ shift(@$r);
+ my $r_k = $r->[0];
+ my $r_v1 = $r->[1];
+ my $r_v2 = $r->[2];
+ print "2ndidx $k $v1 => $r_k $r_v1 $r_v2\n";
+}
+
+print "2ndIDX NULL\n";
+{
+ my %rvals = ();
+ my $v1 = undef;
+ my @arr;
+ push(@arr, undef);
+ my $kv = \@arr;
+ my $r = $hs->execute_single(2, "=", $kv, 10000, 0);
+ shift(@$r);
+ for (my $i = 0; $i < scalar(@$r); $i += 3) {
+ my $k = $r->[$i];
+ my $v1 = $r->[$i + 1];
+ my $v2 = $r->[$i + 2];
+ $rvals{$k} = [ $k, $v1, $v2 ];
+ }
+ for my $i (sort { $a <=> $b } keys %rvals) {
+ my $rec = $rvals{$i};
+ my $k = $rec->[0];
+ my $v1 = $rec->[1];
+ my $v2 = $rec->[2];
+ print "2ndidxnull $k $v2\n";
+ }
+}
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test08.expected b/plugin/handler_socket/regtest/test_01_lib/test08.expected
new file mode 100644
index 00000000..64d705da
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test08.expected
@@ -0,0 +1,2 @@
+[0][k5][v5375]
+[0]
diff --git a/plugin/handler_socket/regtest/test_01_lib/test08.pl b/plugin/handler_socket/regtest/test_01_lib/test08.pl
new file mode 100644
index 00000000..da736ef3
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test08.pl
@@ -0,0 +1,48 @@
+#!/usr/bin/env perl
+
+# vim:sw=2:ai
+
+# test for not-found
+
+BEGIN {
+ push @INC, "../common/";
+};
+
+use strict;
+use warnings;
+use hstest;
+
+my $dbh = hstest::init_testdb();
+my $table = 'hstesttbl';
+my $tablesize = 100;
+$dbh->do(
+ "create table $table (k varchar(30) primary key, v varchar(30) not null) " .
+ "engine = innodb");
+srand(999);
+
+my %valmap = ();
+
+my $sth = $dbh->prepare("insert into $table values (?,?)");
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = "k" . $i;
+ my $v = "v" . int(rand(1000)) . $i;
+ $sth->execute($k, $v);
+ $valmap{$k} = $v;
+}
+
+my $hs = hstest::get_hs_connection();
+my $dbname = $hstest::conf{dbname};
+$hs->open_index(1, $dbname, $table, '', 'k,v');
+
+dump_rec($hs, 1, 'k5'); # found
+dump_rec($hs, 1, 'k000000'); # notfound
+
+sub dump_rec {
+ my ($hs, $idxid, $key) = @_;
+ my $r = $hs->execute_single($idxid, '=', [ $key ], 1, 0);
+ for my $fld (@$r) {
+ print "[$fld]";
+ }
+ print "\n";
+}
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test09.expected b/plugin/handler_socket/regtest/test_01_lib/test09.expected
new file mode 100644
index 00000000..12cb1182
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test09.expected
@@ -0,0 +1,12 @@
+DEL
+[0][1]
+[0][k50][v68250][k51][v93451]
+DELINS
+[0][k6][v5926][k60][v14460][k61][v15261]
+[0][1]
+[0]
+[0][k6][v5926][k60][INS][k61][v15261]
+DELUPUP
+[0][k7][v4147][k70][v41370][k71][v6971]
+[0][1]
+[0][k7][v4147][k70][UP][k71][v6971]
diff --git a/plugin/handler_socket/regtest/test_01_lib/test09.pl b/plugin/handler_socket/regtest/test_01_lib/test09.pl
new file mode 100644
index 00000000..7d6165ec
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test09.pl
@@ -0,0 +1,67 @@
+#!/usr/bin/env perl
+
+# vim:sw=2:ai
+
+# test for multiple modify requests
+
+BEGIN {
+ push @INC, "../common/";
+};
+
+use strict;
+use warnings;
+use hstest;
+
+my $dbh = hstest::init_testdb();
+my $table = 'hstesttbl';
+my $tablesize = 100;
+$dbh->do(
+ "create table $table (k varchar(30) primary key, v varchar(30) not null) " .
+ "engine = innodb");
+srand(999);
+
+my %valmap = ();
+
+my $sth = $dbh->prepare("insert into $table values (?,?)");
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = "k" . $i;
+ my $v = "v" . int(rand(1000)) . $i;
+ $sth->execute($k, $v);
+ $valmap{$k} = $v;
+}
+
+my $hs = hstest::get_hs_connection(undef, 9999);
+my $dbname = $hstest::conf{dbname};
+$hs->open_index(1, $dbname, $table, '', 'k,v');
+
+exec_multi(
+ "DEL",
+ [ 1, '=', [ 'k5' ], 1, 0, 'D' ],
+ [ 1, '>=', [ 'k5' ], 2, 0 ],
+);
+exec_multi(
+ "DELINS",
+ [ 1, '>=', [ 'k6' ], 3, 0 ],
+ [ 1, '=', [ 'k60' ], 1, 0, 'D' ],
+ [ 1, '+', [ 'k60', 'INS' ] ],
+ [ 1, '>=', [ 'k6' ], 3, 0 ],
+);
+exec_multi(
+ "DELUPUP",
+ [ 1, '>=', [ 'k7' ], 3, 0 ],
+ [ 1, '=', [ 'k70' ], 1, 0, 'U', [ 'k70', 'UP' ] ],
+ [ 1, '>=', [ 'k7' ], 3, 0 ],
+);
+
+sub exec_multi {
+ my $mess = shift(@_);
+ print "$mess\n";
+ my $mres = $hs->execute_multi(\@_);
+ for my $res (@$mres) {
+ for my $fld (@$res) {
+ print "[$fld]";
+ }
+ print "\n";
+ }
+}
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test10.expected b/plugin/handler_socket/regtest/test_01_lib/test10.expected
new file mode 100644
index 00000000..6716abad
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test10.expected
@@ -0,0 +1,771 @@
+HSINSERTDUMP_TABLE
+0 v1_0 [null]
+1 v1_1 [null]
+10 v1_10 [null]
+100 v1_100 [null]
+101 v1_101 [null]
+102 v1_102 [null]
+103 v1_103 [null]
+104 v1_104 [null]
+105 v1_105 [null]
+106 v1_106 [null]
+107 v1_107 [null]
+108 v1_108 [null]
+109 v1_109 [null]
+11 v1_11 [null]
+110 v1_110 [null]
+111 v1_111 [null]
+112 v1_112 [null]
+113 v1_113 [null]
+114 v1_114 [null]
+115 v1_115 [null]
+116 v1_116 [null]
+117 v1_117 [null]
+118 v1_118 [null]
+119 v1_119 [null]
+12 v1_12 [null]
+120 v1_120 [null]
+121 v1_121 [null]
+122 v1_122 [null]
+123 v1_123 [null]
+124 v1_124 [null]
+125 v1_125 [null]
+126 v1_126 [null]
+127 v1_127 [null]
+128 v1_128 [null]
+129 v1_129 [null]
+13 v1_13 [null]
+130 v1_130 [null]
+131 v1_131 [null]
+132 v1_132 [null]
+133 v1_133 [null]
+134 v1_134 [null]
+135 v1_135 [null]
+136 v1_136 [null]
+137 v1_137 [null]
+138 v1_138 [null]
+139 v1_139 [null]
+14 v1_14 [null]
+140 v1_140 [null]
+141 v1_141 [null]
+142 v1_142 [null]
+143 v1_143 [null]
+144 v1_144 [null]
+145 v1_145 [null]
+146 v1_146 [null]
+147 v1_147 [null]
+148 v1_148 [null]
+149 v1_149 [null]
+15 v1_15 [null]
+150 v1_150 [null]
+151 v1_151 [null]
+152 v1_152 [null]
+153 v1_153 [null]
+154 v1_154 [null]
+155 v1_155 [null]
+156 v1_156 [null]
+157 v1_157 [null]
+158 v1_158 [null]
+159 v1_159 [null]
+16 v1_16 [null]
+160 v1_160 [null]
+161 v1_161 [null]
+162 v1_162 [null]
+163 v1_163 [null]
+164 v1_164 [null]
+165 v1_165 [null]
+166 v1_166 [null]
+167 v1_167 [null]
+168 v1_168 [null]
+169 v1_169 [null]
+17 v1_17 [null]
+170 v1_170 [null]
+171 v1_171 [null]
+172 v1_172 [null]
+173 v1_173 [null]
+174 v1_174 [null]
+175 v1_175 [null]
+176 v1_176 [null]
+177 v1_177 [null]
+178 v1_178 [null]
+179 v1_179 [null]
+18 v1_18 [null]
+180 v1_180 [null]
+181 v1_181 [null]
+182 v1_182 [null]
+183 v1_183 [null]
+184 v1_184 [null]
+185 v1_185 [null]
+186 v1_186 [null]
+187 v1_187 [null]
+188 v1_188 [null]
+189 v1_189 [null]
+19 v1_19 [null]
+190 v1_190 [null]
+191 v1_191 [null]
+192 v1_192 [null]
+193 v1_193 [null]
+194 v1_194 [null]
+195 v1_195 [null]
+196 v1_196 [null]
+197 v1_197 [null]
+198 v1_198 [null]
+199 v1_199 [null]
+2 v1_2 [null]
+20 v1_20 [null]
+200 v1_200 [null]
+201 v1_201 [null]
+202 v1_202 [null]
+203 v1_203 [null]
+204 v1_204 [null]
+205 v1_205 [null]
+206 v1_206 [null]
+207 v1_207 [null]
+208 v1_208 [null]
+209 v1_209 [null]
+21 v1_21 [null]
+210 v1_210 [null]
+211 v1_211 [null]
+212 v1_212 [null]
+213 v1_213 [null]
+214 v1_214 [null]
+215 v1_215 [null]
+216 v1_216 [null]
+217 v1_217 [null]
+218 v1_218 [null]
+219 v1_219 [null]
+22 v1_22 [null]
+220 v1_220 [null]
+221 v1_221 [null]
+222 v1_222 [null]
+223 v1_223 [null]
+224 v1_224 [null]
+225 v1_225 [null]
+226 v1_226 [null]
+227 v1_227 [null]
+228 v1_228 [null]
+229 v1_229 [null]
+23 v1_23 [null]
+230 v1_230 [null]
+231 v1_231 [null]
+232 v1_232 [null]
+233 v1_233 [null]
+234 v1_234 [null]
+235 v1_235 [null]
+236 v1_236 [null]
+237 v1_237 [null]
+238 v1_238 [null]
+239 v1_239 [null]
+24 v1_24 [null]
+240 v1_240 [null]
+241 v1_241 [null]
+242 v1_242 [null]
+243 v1_243 [null]
+244 v1_244 [null]
+245 v1_245 [null]
+246 v1_246 [null]
+247 v1_247 [null]
+248 v1_248 [null]
+249 v1_249 [null]
+25 v1_25 [null]
+250 v1_250 [null]
+251 v1_251 [null]
+252 v1_252 [null]
+253 v1_253 [null]
+254 v1_254 [null]
+255 v1_255 [null]
+26 v1_26 [null]
+27 v1_27 [null]
+28 v1_28 [null]
+29 v1_29 [null]
+3 v1_3 [null]
+30 v1_30 [null]
+31 v1_31 [null]
+32 v1_32 [null]
+33 v1_33 [null]
+34 v1_34 [null]
+35 v1_35 [null]
+36 v1_36 [null]
+37 v1_37 [null]
+38 v1_38 [null]
+39 v1_39 [null]
+4 v1_4 [null]
+40 v1_40 [null]
+41 v1_41 [null]
+42 v1_42 [null]
+43 v1_43 [null]
+44 v1_44 [null]
+45 v1_45 [null]
+46 v1_46 [null]
+47 v1_47 [null]
+48 v1_48 [null]
+49 v1_49 [null]
+5 v1_5 [null]
+50 v1_50 [null]
+51 v1_51 [null]
+52 v1_52 [null]
+53 v1_53 [null]
+54 v1_54 [null]
+55 v1_55 [null]
+56 v1_56 [null]
+57 v1_57 [null]
+58 v1_58 [null]
+59 v1_59 [null]
+6 v1_6 [null]
+60 v1_60 [null]
+61 v1_61 [null]
+62 v1_62 [null]
+63 v1_63 [null]
+64 v1_64 [null]
+65 v1_65 [null]
+66 v1_66 [null]
+67 v1_67 [null]
+68 v1_68 [null]
+69 v1_69 [null]
+7 v1_7 [null]
+70 v1_70 [null]
+71 v1_71 [null]
+72 v1_72 [null]
+73 v1_73 [null]
+74 v1_74 [null]
+75 v1_75 [null]
+76 v1_76 [null]
+77 v1_77 [null]
+78 v1_78 [null]
+79 v1_79 [null]
+8 v1_8 [null]
+80 v1_80 [null]
+81 v1_81 [null]
+82 v1_82 [null]
+83 v1_83 [null]
+84 v1_84 [null]
+85 v1_85 [null]
+86 v1_86 [null]
+87 v1_87 [null]
+88 v1_88 [null]
+89 v1_89 [null]
+9 v1_9 [null]
+90 v1_90 [null]
+91 v1_91 [null]
+92 v1_92 [null]
+93 v1_93 [null]
+94 v1_94 [null]
+95 v1_95 [null]
+96 v1_96 [null]
+97 v1_97 [null]
+98 v1_98 [null]
+99 v1_99 [null]
+HSUPDATEDUMP_TABLE
+0 [null] [null]
+1 [null] [null]
+10 [null] [null]
+100 [null] [null]
+101 [null] [null]
+102 [null] [null]
+103 [null] [null]
+104 [null] [null]
+105 [null] [null]
+106 [null] [null]
+107 [null] [null]
+108 [null] [null]
+109 [null] [null]
+11 [null] [null]
+110 [null] [null]
+111 [null] [null]
+112 [null] [null]
+113 [null] [null]
+114 [null] [null]
+115 [null] [null]
+116 [null] [null]
+117 [null] [null]
+118 [null] [null]
+119 [null] [null]
+12 [null] [null]
+120 [null] [null]
+121 [null] [null]
+122 [null] [null]
+123 [null] [null]
+124 [null] [null]
+125 [null] [null]
+126 [null] [null]
+127 [null] [null]
+128 [null] [null]
+129 [null] [null]
+13 [null] [null]
+130 [null] [null]
+131 [null] [null]
+132 [null] [null]
+133 [null] [null]
+134 [null] [null]
+135 [null] [null]
+136 [null] [null]
+137 [null] [null]
+138 [null] [null]
+139 [null] [null]
+14 [null] [null]
+140 [null] [null]
+141 [null] [null]
+142 [null] [null]
+143 [null] [null]
+144 [null] [null]
+145 [null] [null]
+146 [null] [null]
+147 [null] [null]
+148 [null] [null]
+149 [null] [null]
+15 [null] [null]
+150 [null] [null]
+151 [null] [null]
+152 [null] [null]
+153 [null] [null]
+154 [null] [null]
+155 [null] [null]
+156 [null] [null]
+157 [null] [null]
+158 [null] [null]
+159 [null] [null]
+16 [null] [null]
+160 [null] [null]
+161 [null] [null]
+162 [null] [null]
+163 [null] [null]
+164 [null] [null]
+165 [null] [null]
+166 [null] [null]
+167 [null] [null]
+168 [null] [null]
+169 [null] [null]
+17 [null] [null]
+170 [null] [null]
+171 [null] [null]
+172 [null] [null]
+173 [null] [null]
+174 [null] [null]
+175 [null] [null]
+176 [null] [null]
+177 [null] [null]
+178 [null] [null]
+179 [null] [null]
+18 [null] [null]
+180 [null] [null]
+181 [null] [null]
+182 [null] [null]
+183 [null] [null]
+184 [null] [null]
+185 [null] [null]
+186 [null] [null]
+187 [null] [null]
+188 [null] [null]
+189 [null] [null]
+19 [null] [null]
+190 [null] [null]
+191 [null] [null]
+192 [null] [null]
+193 [null] [null]
+194 [null] [null]
+195 [null] [null]
+196 [null] [null]
+197 [null] [null]
+198 [null] [null]
+199 [null] [null]
+2 [null] [null]
+20 [null] [null]
+200 [null] [null]
+201 [null] [null]
+202 [null] [null]
+203 [null] [null]
+204 [null] [null]
+205 [null] [null]
+206 [null] [null]
+207 [null] [null]
+208 [null] [null]
+209 [null] [null]
+21 [null] [null]
+210 [null] [null]
+211 [null] [null]
+212 [null] [null]
+213 [null] [null]
+214 [null] [null]
+215 [null] [null]
+216 [null] [null]
+217 [null] [null]
+218 [null] [null]
+219 [null] [null]
+22 [null] [null]
+220 [null] [null]
+221 [null] [null]
+222 [null] [null]
+223 [null] [null]
+224 [null] [null]
+225 [null] [null]
+226 [null] [null]
+227 [null] [null]
+228 [null] [null]
+229 [null] [null]
+23 [null] [null]
+230 [null] [null]
+231 [null] [null]
+232 [null] [null]
+233 [null] [null]
+234 [null] [null]
+235 [null] [null]
+236 [null] [null]
+237 [null] [null]
+238 [null] [null]
+239 [null] [null]
+24 [null] [null]
+240 [null] [null]
+241 [null] [null]
+242 [null] [null]
+243 [null] [null]
+244 [null] [null]
+245 [null] [null]
+246 [null] [null]
+247 [null] [null]
+248 [null] [null]
+249 [null] [null]
+25 [null] [null]
+250 [null] [null]
+251 [null] [null]
+252 [null] [null]
+253 [null] [null]
+254 [null] [null]
+255 [null] [null]
+26 [null] [null]
+27 [null] [null]
+28 [null] [null]
+29 [null] [null]
+3 [null] [null]
+30 [null] [null]
+31 [null] [null]
+32 [null] [null]
+33 [null] [null]
+34 [null] [null]
+35 [null] [null]
+36 [null] [null]
+37 [null] [null]
+38 [null] [null]
+39 [null] [null]
+4 [null] [null]
+40 [null] [null]
+41 [null] [null]
+42 [null] [null]
+43 [null] [null]
+44 [null] [null]
+45 [null] [null]
+46 [null] [null]
+47 [null] [null]
+48 [null] [null]
+49 [null] [null]
+5 [null] [null]
+50 [null] [null]
+51 [null] [null]
+52 [null] [null]
+53 [null] [null]
+54 [null] [null]
+55 [null] [null]
+56 [null] [null]
+57 [null] [null]
+58 [null] [null]
+59 [null] [null]
+6 [null] [null]
+60 [null] [null]
+61 [null] [null]
+62 [null] [null]
+63 [null] [null]
+64 [null] [null]
+65 [null] [null]
+66 [null] [null]
+67 [null] [null]
+68 [null] [null]
+69 [null] [null]
+7 [null] [null]
+70 [null] [null]
+71 [null] [null]
+72 [null] [null]
+73 [null] [null]
+74 [null] [null]
+75 [null] [null]
+76 [null] [null]
+77 [null] [null]
+78 [null] [null]
+79 [null] [null]
+8 [null] [null]
+80 [null] [null]
+81 [null] [null]
+82 [null] [null]
+83 [null] [null]
+84 [null] [null]
+85 [null] [null]
+86 [null] [null]
+87 [null] [null]
+88 [null] [null]
+89 [null] [null]
+9 [null] [null]
+90 [null] [null]
+91 [null] [null]
+92 [null] [null]
+93 [null] [null]
+94 [null] [null]
+95 [null] [null]
+96 [null] [null]
+97 [null] [null]
+98 [null] [null]
+99 [null] [null]
+HSUPDATEDUMP_TABLE
+0 hoge [null]
+1 hoge [null]
+10 hoge [null]
+100 hoge [null]
+101 hoge [null]
+102 hoge [null]
+103 hoge [null]
+104 hoge [null]
+105 hoge [null]
+106 hoge [null]
+107 hoge [null]
+108 hoge [null]
+109 hoge [null]
+11 hoge [null]
+110 hoge [null]
+111 hoge [null]
+112 hoge [null]
+113 hoge [null]
+114 hoge [null]
+115 hoge [null]
+116 hoge [null]
+117 hoge [null]
+118 hoge [null]
+119 hoge [null]
+12 hoge [null]
+120 hoge [null]
+121 hoge [null]
+122 hoge [null]
+123 hoge [null]
+124 hoge [null]
+125 hoge [null]
+126 hoge [null]
+127 hoge [null]
+128 hoge [null]
+129 hoge [null]
+13 hoge [null]
+130 hoge [null]
+131 hoge [null]
+132 hoge [null]
+133 hoge [null]
+134 hoge [null]
+135 hoge [null]
+136 hoge [null]
+137 hoge [null]
+138 hoge [null]
+139 hoge [null]
+14 hoge [null]
+140 hoge [null]
+141 hoge [null]
+142 hoge [null]
+143 hoge [null]
+144 hoge [null]
+145 hoge [null]
+146 hoge [null]
+147 hoge [null]
+148 hoge [null]
+149 hoge [null]
+15 hoge [null]
+150 hoge [null]
+151 hoge [null]
+152 hoge [null]
+153 hoge [null]
+154 hoge [null]
+155 hoge [null]
+156 hoge [null]
+157 hoge [null]
+158 hoge [null]
+159 hoge [null]
+16 hoge [null]
+160 hoge [null]
+161 hoge [null]
+162 hoge [null]
+163 hoge [null]
+164 hoge [null]
+165 hoge [null]
+166 hoge [null]
+167 hoge [null]
+168 hoge [null]
+169 hoge [null]
+17 hoge [null]
+170 hoge [null]
+171 hoge [null]
+172 hoge [null]
+173 hoge [null]
+174 hoge [null]
+175 hoge [null]
+176 hoge [null]
+177 hoge [null]
+178 hoge [null]
+179 hoge [null]
+18 hoge [null]
+180 hoge [null]
+181 hoge [null]
+182 hoge [null]
+183 hoge [null]
+184 hoge [null]
+185 hoge [null]
+186 hoge [null]
+187 hoge [null]
+188 hoge [null]
+189 hoge [null]
+19 hoge [null]
+190 hoge [null]
+191 hoge [null]
+192 hoge [null]
+193 hoge [null]
+194 hoge [null]
+195 hoge [null]
+196 hoge [null]
+197 hoge [null]
+198 hoge [null]
+199 hoge [null]
+2 hoge [null]
+20 hoge [null]
+200 hoge [null]
+201 hoge [null]
+202 hoge [null]
+203 hoge [null]
+204 hoge [null]
+205 hoge [null]
+206 hoge [null]
+207 hoge [null]
+208 hoge [null]
+209 hoge [null]
+21 hoge [null]
+210 hoge [null]
+211 hoge [null]
+212 hoge [null]
+213 hoge [null]
+214 hoge [null]
+215 hoge [null]
+216 hoge [null]
+217 hoge [null]
+218 hoge [null]
+219 hoge [null]
+22 hoge [null]
+220 hoge [null]
+221 hoge [null]
+222 hoge [null]
+223 hoge [null]
+224 hoge [null]
+225 hoge [null]
+226 hoge [null]
+227 hoge [null]
+228 hoge [null]
+229 hoge [null]
+23 hoge [null]
+230 hoge [null]
+231 hoge [null]
+232 hoge [null]
+233 hoge [null]
+234 hoge [null]
+235 hoge [null]
+236 hoge [null]
+237 hoge [null]
+238 hoge [null]
+239 hoge [null]
+24 hoge [null]
+240 hoge [null]
+241 hoge [null]
+242 hoge [null]
+243 hoge [null]
+244 hoge [null]
+245 hoge [null]
+246 hoge [null]
+247 hoge [null]
+248 hoge [null]
+249 hoge [null]
+25 hoge [null]
+250 hoge [null]
+251 hoge [null]
+252 hoge [null]
+253 hoge [null]
+254 hoge [null]
+255 hoge [null]
+26 hoge [null]
+27 hoge [null]
+28 hoge [null]
+29 hoge [null]
+3 hoge [null]
+30 hoge [null]
+31 hoge [null]
+32 hoge [null]
+33 hoge [null]
+34 hoge [null]
+35 hoge [null]
+36 hoge [null]
+37 hoge [null]
+38 hoge [null]
+39 hoge [null]
+4 hoge [null]
+40 hoge [null]
+41 hoge [null]
+42 hoge [null]
+43 hoge [null]
+44 hoge [null]
+45 hoge [null]
+46 hoge [null]
+47 hoge [null]
+48 hoge [null]
+49 hoge [null]
+5 hoge [null]
+50 hoge [null]
+51 hoge [null]
+52 hoge [null]
+53 hoge [null]
+54 hoge [null]
+55 hoge [null]
+56 hoge [null]
+57 hoge [null]
+58 hoge [null]
+59 hoge [null]
+6 hoge [null]
+60 hoge [null]
+61 hoge [null]
+62 hoge [null]
+63 hoge [null]
+64 hoge [null]
+65 hoge [null]
+66 hoge [null]
+67 hoge [null]
+68 hoge [null]
+69 hoge [null]
+7 hoge [null]
+70 hoge [null]
+71 hoge [null]
+72 hoge [null]
+73 hoge [null]
+74 hoge [null]
+75 hoge [null]
+76 hoge [null]
+77 hoge [null]
+78 hoge [null]
+79 hoge [null]
+8 hoge [null]
+80 hoge [null]
+81 hoge [null]
+82 hoge [null]
+83 hoge [null]
+84 hoge [null]
+85 hoge [null]
+86 hoge [null]
+87 hoge [null]
+88 hoge [null]
+89 hoge [null]
+9 hoge [null]
+90 hoge [null]
+91 hoge [null]
+92 hoge [null]
+93 hoge [null]
+94 hoge [null]
+95 hoge [null]
+96 hoge [null]
+97 hoge [null]
+98 hoge [null]
+99 hoge [null]
diff --git a/plugin/handler_socket/regtest/test_01_lib/test10.pl b/plugin/handler_socket/regtest/test_01_lib/test10.pl
new file mode 100644
index 00000000..560976ba
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test10.pl
@@ -0,0 +1,93 @@
+#!/usr/bin/env perl
+
+# vim:sw=2:ai
+
+# test for nulls
+
+BEGIN {
+ push @INC, "../common/";
+};
+
+use strict;
+use warnings;
+use hstest;
+
+my $dbh = hstest::init_testdb();
+my $table = 'hstesttbl';
+my $tablesize = 256;
+$dbh->do(
+ "create table $table (" .
+ "k varchar(30) primary key, " .
+ "v1 varchar(30), " .
+ "v2 varchar(30)) " .
+ "engine = innodb default charset = binary");
+srand(999);
+
+my %valmap = ();
+
+# setting null
+print "HSINSERT";
+my $hs = hstest::get_hs_connection(undef, 9999);
+my $dbname = $hstest::conf{dbname};
+$hs->open_index(1, $dbname, $table, '', 'k,v1,v2');
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = "" . $i;
+ my $v1 = "v1_" . $i;
+ my $v2 = undef; # null value
+ my $r = $hs->execute_insert(1, [ $k, $v1, $v2 ]);
+ my $err = $r->[0];
+ if ($err != 0) {
+ my $err_str = $r->[1];
+ print "$err $err_str\n";
+ }
+}
+undef $hs;
+
+dump_table();
+
+# setting null
+print "HSUPDATE";
+$hs = hstest::get_hs_connection(undef, 9999);
+$dbname = $hstest::conf{dbname};
+$hs->open_index(2, $dbname, $table, '', 'v1');
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $r = $hs->execute_single(2, '=', [ $i ], 1000, 0, 'U', [ undef ]);
+ my $err = $r->[0];
+ if ($err != 0) {
+ my $err_str = $r->[1];
+ print "$err $err_str\n";
+ }
+}
+undef $hs;
+
+dump_table();
+
+# setting non-null
+print "HSUPDATE";
+$hs = hstest::get_hs_connection(undef, 9999);
+$dbname = $hstest::conf{dbname};
+$hs->open_index(2, $dbname, $table, '', 'v1');
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $r = $hs->execute_single(2, '=', [ $i ], 1000, 0, 'U', [ "hoge" ]);
+ my $err = $r->[0];
+ if ($err != 0) {
+ my $err_str = $r->[1];
+ print "$err $err_str\n";
+ }
+}
+undef $hs;
+
+dump_table();
+
+sub dump_table {
+ print "DUMP_TABLE\n";
+ my $aref = $dbh->selectall_arrayref("select k,v1,v2 from $table order by k");
+ for my $row (@$aref) {
+ my ($k, $v1, $v2) = @$row;
+ $v1 = "[null]" if !defined($v1);
+ $v2 = "[null]" if !defined($v2);
+ print "$k $v1 $v2\n";
+ # print "MISMATCH\n" if ($valmap{$k} ne $v);
+ }
+}
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test11.expected b/plugin/handler_socket/regtest/test_01_lib/test11.expected
new file mode 100644
index 00000000..4359d470
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test11.expected
@@ -0,0 +1,37 @@
+VAL
+[0][k5][5]
+[0][k6][6]
+[0][k7][7]
+[0][k8][8]
+INCREMENT
+[0][1]
+[0][1]
+[0][1]
+[0][1]
+VAL
+[0][k5][8]
+[0][k6][18]
+[0][k7][-4]
+[0][k8][-7]
+DECREMENT
+[0][1]
+[0][0]
+[0][1]
+[0][0]
+VAL
+[0][k5][6]
+[0][k6][18]
+[0][k7][-84]
+[0][k8][-7]
+INCREMENT
+[0][6]
+[0][7]
+[0][8]
+[0][9]
+[0][10]
+[0][11]
+[0][12]
+[0][13]
+[0][14]
+VAL
+[0][k5][15]
diff --git a/plugin/handler_socket/regtest/test_01_lib/test11.pl b/plugin/handler_socket/regtest/test_01_lib/test11.pl
new file mode 100644
index 00000000..cfaa9405
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test11.pl
@@ -0,0 +1,112 @@
+#!/usr/bin/env perl
+
+# vim:sw=2:ai
+
+# test for increment/decrement
+
+BEGIN {
+ push @INC, "../common/";
+};
+
+use strict;
+use warnings;
+use hstest;
+
+my $dbh = hstest::init_testdb();
+my $table = 'hstesttbl';
+my $tablesize = 100;
+$dbh->do(
+ "create table $table (k varchar(30) primary key, v varchar(30) not null) " .
+ "engine = innodb");
+srand(999);
+
+my %valmap = ();
+
+my $sth = $dbh->prepare("insert into $table values (?,?)");
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = "k" . $i;
+ my $v = $i;
+ $sth->execute($k, $v);
+ $valmap{$k} = $v;
+}
+
+my $hs = hstest::get_hs_connection(undef, 9999);
+my $dbname = $hstest::conf{dbname};
+$hs->open_index(1, $dbname, $table, '', 'k,v');
+$hs->open_index(2, $dbname, $table, '', 'v');
+
+exec_multi(
+ "VAL",
+ [ 1, '=', [ 'k5' ], 1, 0 ],
+ [ 1, '=', [ 'k6' ], 1, 0 ],
+ [ 1, '=', [ 'k7' ], 1, 0 ],
+ [ 1, '=', [ 'k8' ], 1, 0 ],
+);
+# 5, 6, 7, 8
+
+exec_multi(
+ "INCREMENT",
+ [ 2, '=', [ 'k5' ], 1, 0, '+', [ 3 ] ],
+ [ 2, '=', [ 'k6' ], 1, 0, '+', [ 12 ] ],
+ [ 2, '=', [ 'k7' ], 1, 0, '+', [ -11 ] ],
+ [ 2, '=', [ 'k8' ], 1, 0, '+', [ -15 ] ],
+);
+
+exec_multi(
+ "VAL",
+ [ 1, '=', [ 'k5' ], 1, 0 ],
+ [ 1, '=', [ 'k6' ], 1, 0 ],
+ [ 1, '=', [ 'k7' ], 1, 0 ],
+ [ 1, '=', [ 'k8' ], 1, 0 ],
+);
+# 8, 18, -4, -7
+
+exec_multi(
+ "DECREMENT",
+ [ 2, '=', [ 'k5' ], 1, 0, '-', [ 2 ] ],
+ [ 2, '=', [ 'k6' ], 1, 0, '-', [ 24 ] ],
+ [ 2, '=', [ 'k7' ], 1, 0, '-', [ 80 ] ],
+ [ 2, '=', [ 'k8' ], 1, 0, '-', [ -80 ] ],
+);
+# mod, no, mod, no
+
+exec_multi(
+ "VAL",
+ [ 1, '=', [ 'k5' ], 1, 0 ],
+ [ 1, '=', [ 'k6' ], 1, 0 ],
+ [ 1, '=', [ 'k7' ], 1, 0 ],
+ [ 1, '=', [ 'k8' ], 1, 0 ],
+);
+# 6, 18, -84, -7
+
+exec_multi(
+ "INCREMENT",
+ [ 2, '=', [ 'k5' ], 1, 0, '+?', [ 1 ] ],
+ [ 2, '=', [ 'k5' ], 1, 0, '+?', [ 1 ] ],
+ [ 2, '=', [ 'k5' ], 1, 0, '+?', [ 1 ] ],
+ [ 2, '=', [ 'k5' ], 1, 0, '+?', [ 1 ] ],
+ [ 2, '=', [ 'k5' ], 1, 0, '+?', [ 1 ] ],
+ [ 2, '=', [ 'k5' ], 1, 0, '+?', [ 1 ] ],
+ [ 2, '=', [ 'k5' ], 1, 0, '+?', [ 1 ] ],
+ [ 2, '=', [ 'k5' ], 1, 0, '+?', [ 1 ] ],
+ [ 2, '=', [ 'k5' ], 1, 0, '+?', [ 1 ] ],
+);
+
+exec_multi(
+ "VAL",
+ [ 1, '=', [ 'k5' ], 1, 0 ],
+);
+# 15
+
+sub exec_multi {
+ my $mess = shift(@_);
+ print "$mess\n";
+ my $mres = $hs->execute_multi(\@_);
+ for my $res (@$mres) {
+ for my $fld (@$res) {
+ print "[$fld]";
+ }
+ print "\n";
+ }
+}
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test12.expected b/plugin/handler_socket/regtest/test_01_lib/test12.expected
new file mode 100644
index 00000000..96002e79
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test12.expected
@@ -0,0 +1,273 @@
+VAL
+code=0
+[k1_0][k2_0][0][0]
+[k1_0][k2_1][1][0]
+[k1_0][k2_2][2][0]
+[k1_0][k2_3][3][0]
+[k1_0][k2_4][4][0]
+[k1_0][k2_5][5][0]
+[k1_0][k2_6][6][0]
+[k1_0][k2_7][7][0]
+[k1_0][k2_8][8][0]
+[k1_0][k2_9][9][0]
+[k1_1][k2_0][1][0]
+[k1_1][k2_1][2][1]
+[k1_1][k2_2][3][2]
+[k1_1][k2_3][4][3]
+[k1_1][k2_4][5][4]
+[k1_1][k2_5][6][5]
+[k1_1][k2_6][7][6]
+[k1_1][k2_7][8][7]
+[k1_1][k2_8][9][8]
+[k1_1][k2_9][10][9]
+[k1_2][k2_0][2][0]
+[k1_2][k2_1][3][2]
+[k1_2][k2_2][4][4]
+[k1_2][k2_3][5][6]
+[k1_2][k2_4][6][8]
+[k1_2][k2_5][7][10]
+[k1_2][k2_6][8][12]
+[k1_2][k2_7][9][14]
+[k1_2][k2_8][10][16]
+[k1_2][k2_9][11][18]
+[k1_3][k2_0][3][0]
+[k1_3][k2_1][4][3]
+[k1_3][k2_2][5][6]
+[k1_3][k2_3][6][9]
+[k1_3][k2_4][7][12]
+[k1_3][k2_5][8][15]
+[k1_3][k2_6][9][18]
+[k1_3][k2_7][10][21]
+[k1_3][k2_8][11][24]
+[k1_3][k2_9][12][27]
+[k1_4][k2_0][4][0]
+[k1_4][k2_1][5][4]
+[k1_4][k2_2][6][8]
+[k1_4][k2_3][7][12]
+[k1_4][k2_4][8][16]
+[k1_4][k2_5][9][20]
+[k1_4][k2_6][10][24]
+[k1_4][k2_7][11][28]
+[k1_4][k2_8][12][32]
+[k1_4][k2_9][13][36]
+[k1_5][k2_0][5][0]
+[k1_5][k2_1][6][5]
+[k1_5][k2_2][7][10]
+[k1_5][k2_3][8][15]
+[k1_5][k2_4][9][20]
+[k1_5][k2_5][10][25]
+[k1_5][k2_6][11][30]
+[k1_5][k2_7][12][35]
+[k1_5][k2_8][13][40]
+[k1_5][k2_9][14][45]
+[k1_6][k2_0][6][0]
+[k1_6][k2_1][7][6]
+[k1_6][k2_2][8][12]
+[k1_6][k2_3][9][18]
+[k1_6][k2_4][10][24]
+[k1_6][k2_5][11][30]
+[k1_6][k2_6][12][36]
+[k1_6][k2_7][13][42]
+[k1_6][k2_8][14][48]
+[k1_6][k2_9][15][54]
+[k1_7][k2_0][7][0]
+[k1_7][k2_1][8][7]
+[k1_7][k2_2][9][14]
+[k1_7][k2_3][10][21]
+[k1_7][k2_4][11][28]
+[k1_7][k2_5][12][35]
+[k1_7][k2_6][13][42]
+[k1_7][k2_7][14][49]
+[k1_7][k2_8][15][56]
+[k1_7][k2_9][16][63]
+[k1_8][k2_0][8][0]
+[k1_8][k2_1][9][8]
+[k1_8][k2_2][10][16]
+[k1_8][k2_3][11][24]
+[k1_8][k2_4][12][32]
+[k1_8][k2_5][13][40]
+[k1_8][k2_6][14][48]
+[k1_8][k2_7][15][56]
+[k1_8][k2_8][16][64]
+[k1_8][k2_9][17][72]
+[k1_9][k2_0][9][0]
+[k1_9][k2_1][10][9]
+[k1_9][k2_2][11][18]
+[k1_9][k2_3][12][27]
+[k1_9][k2_4][13][36]
+[k1_9][k2_5][14][45]
+[k1_9][k2_6][15][54]
+[k1_9][k2_7][16][63]
+[k1_9][k2_8][17][72]
+[k1_9][k2_9][18][81]
+
+FILTER
+code=0
+[k1_0][k2_5][5][0]
+[k1_1][k2_5][6][5]
+[k1_2][k2_5][7][10]
+[k1_3][k2_5][8][15]
+[k1_4][k2_5][9][20]
+[k1_5][k2_5][10][25]
+[k1_6][k2_5][11][30]
+[k1_7][k2_5][12][35]
+[k1_8][k2_5][13][40]
+[k1_9][k2_5][14][45]
+
+FILTER
+code=0
+[k1_0][k2_5][5][0]
+[k1_1][k2_5][6][5]
+[k1_2][k2_5][7][10]
+[k1_3][k2_5][8][15]
+[k1_4][k2_5][9][20]
+[k1_5][k2_5][10][25]
+[k1_6][k2_5][11][30]
+[k1_7][k2_5][12][35]
+[k1_8][k2_5][13][40]
+[k1_9][k2_5][14][45]
+
+FILTER
+code=0
+[k1_0][k2_3][3][0]
+[k1_1][k2_2][3][2]
+[k1_2][k2_1][3][2]
+[k1_3][k2_0][3][0]
+
+FILTER
+code=0
+[k1_1][k2_0][1][0]
+[k1_1][k2_1][2][1]
+[k1_1][k2_2][3][2]
+[k1_1][k2_3][4][3]
+[k1_1][k2_4][5][4]
+[k1_1][k2_5][6][5]
+[k1_1][k2_6][7][6]
+[k1_1][k2_7][8][7]
+[k1_1][k2_8][9][8]
+[k1_1][k2_9][10][9]
+[k1_2][k2_0][2][0]
+[k1_2][k2_1][3][2]
+[k1_2][k2_2][4][4]
+[k1_2][k2_3][5][6]
+[k1_2][k2_4][6][8]
+[k1_2][k2_5][7][10]
+[k1_2][k2_6][8][12]
+[k1_2][k2_7][9][14]
+[k1_2][k2_8][10][16]
+[k1_2][k2_9][11][18]
+
+FILTER
+code=0
+[k1_2][k2_5][7][10]
+[k1_2][k2_6][8][12]
+[k1_2][k2_7][9][14]
+[k1_2][k2_8][10][16]
+[k1_2][k2_9][11][18]
+
+FILTER
+code=0
+[2]
+VAL
+code=0
+[k1_0][k2_0][0][0]
+[k1_0][k2_1][1][0]
+[k1_0][k2_2][2][0]
+[k1_0][k2_3][3][0]
+[k1_0][k2_4][4][0]
+[k1_0][k2_5][5][0]
+[k1_0][k2_6][6][0]
+[k1_0][k2_7][7][0]
+[k1_0][k2_8][8][0]
+[k1_0][k2_9][9][0]
+[k1_1][k2_0][1][0]
+[k1_1][k2_1][2][1]
+[k1_1][k2_2][3][2]
+[k1_1][k2_3][4][3]
+[k1_1][k2_4][5][4]
+[k1_1][k2_5][6][5]
+[k1_1][k2_6][7][6]
+[k1_1][k2_7][8][7]
+[k1_1][k2_8][9][8]
+[k1_1][k2_9][10][9]
+[k1_2][k2_0][2][0]
+[k1_2][k2_1][3][2]
+[k1_2][k2_2][4][4]
+[k1_2][k2_3][5][6]
+[k1_2][k2_4][6][8]
+[k1_2][k2_5][-1][10]
+[k1_2][k2_6][8][12]
+[k1_2][k2_7][9][14]
+[k1_2][k2_8][10][16]
+[k1_2][k2_9][11][18]
+[k1_3][k2_0][3][0]
+[k1_3][k2_1][4][3]
+[k1_3][k2_2][5][6]
+[k1_3][k2_3][6][9]
+[k1_3][k2_4][7][12]
+[k1_3][k2_5][8][15]
+[k1_3][k2_6][9][18]
+[k1_3][k2_7][10][21]
+[k1_3][k2_8][11][24]
+[k1_3][k2_9][12][27]
+[k1_4][k2_0][4][0]
+[k1_4][k2_1][5][4]
+[k1_4][k2_2][6][8]
+[k1_4][k2_3][7][12]
+[k1_4][k2_4][8][16]
+[k1_4][k2_5][9][20]
+[k1_4][k2_6][10][24]
+[k1_4][k2_7][11][28]
+[k1_4][k2_8][12][32]
+[k1_4][k2_9][13][36]
+[k1_5][k2_0][5][0]
+[k1_5][k2_1][6][5]
+[k1_5][k2_2][-1][10]
+[k1_5][k2_3][8][15]
+[k1_5][k2_4][9][20]
+[k1_5][k2_5][10][25]
+[k1_5][k2_6][11][30]
+[k1_5][k2_7][12][35]
+[k1_5][k2_8][13][40]
+[k1_5][k2_9][14][45]
+[k1_6][k2_0][6][0]
+[k1_6][k2_1][7][6]
+[k1_6][k2_2][8][12]
+[k1_6][k2_3][9][18]
+[k1_6][k2_4][10][24]
+[k1_6][k2_5][11][30]
+[k1_6][k2_6][12][36]
+[k1_6][k2_7][13][42]
+[k1_6][k2_8][14][48]
+[k1_6][k2_9][15][54]
+[k1_7][k2_0][7][0]
+[k1_7][k2_1][8][7]
+[k1_7][k2_2][9][14]
+[k1_7][k2_3][10][21]
+[k1_7][k2_4][11][28]
+[k1_7][k2_5][12][35]
+[k1_7][k2_6][13][42]
+[k1_7][k2_7][14][49]
+[k1_7][k2_8][15][56]
+[k1_7][k2_9][16][63]
+[k1_8][k2_0][8][0]
+[k1_8][k2_1][9][8]
+[k1_8][k2_2][10][16]
+[k1_8][k2_3][11][24]
+[k1_8][k2_4][12][32]
+[k1_8][k2_5][13][40]
+[k1_8][k2_6][14][48]
+[k1_8][k2_7][15][56]
+[k1_8][k2_8][16][64]
+[k1_8][k2_9][17][72]
+[k1_9][k2_0][9][0]
+[k1_9][k2_1][10][9]
+[k1_9][k2_2][11][18]
+[k1_9][k2_3][12][27]
+[k1_9][k2_4][13][36]
+[k1_9][k2_5][14][45]
+[k1_9][k2_6][15][54]
+[k1_9][k2_7][16][63]
+[k1_9][k2_8][17][72]
+[k1_9][k2_9][18][81]
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test12.pl b/plugin/handler_socket/regtest/test_01_lib/test12.pl
new file mode 100644
index 00000000..0cae3798
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test12.pl
@@ -0,0 +1,134 @@
+#!/usr/bin/env perl
+
+# vim:sw=2:ai
+
+# test for filters
+
+BEGIN {
+ push @INC, "../common/";
+};
+
+use strict;
+use warnings;
+use hstest;
+
+my $dbh = hstest::init_testdb();
+my $table = 'hstesttbl';
+my $tablesize = 10;
+$dbh->do(
+ "create table $table " .
+ "(k1 varchar(30) not null, k2 varchar(30) not null, " .
+ "v1 int not null, v2 int not null, " .
+ "primary key (k1, k2) ) engine = innodb");
+srand(999);
+
+my $sth = $dbh->prepare("insert into $table values (?,?,?,?)");
+for (my $i = 0; $i < $tablesize; ++$i) {
+ for (my $j = 0; $j < $tablesize; ++$j) {
+ my $k1 = "k1_" . $i;
+ my $k2 = "k2_" . $j;
+ my $v1 = $i + $j;
+ my $v2 = $i * $j;
+ $sth->execute($k1, $k2, $v1, $v2);
+ }
+}
+
+my $hs = hstest::get_hs_connection(undef, 9999);
+my $dbname = $hstest::conf{dbname};
+$hs->open_index(1, $dbname, $table, '', 'k1,k2,v1,v2', 'k2');
+$hs->open_index(2, $dbname, $table, '', 'k1,k2,v1,v2', 'k1,k2,v1,v2');
+$hs->open_index(3, $dbname, $table, '', 'v1', 'k1,v2');
+
+exec_multi(
+ 4, "VAL",
+ [ 1, '>=', [ '', '' ], 1000, 0 ],
+);
+# all
+
+# select k1, k2, v1, v2 ... where (k1, k2) >= ('', '') and k2 = 'k2_5'
+exec_single(
+ 4, "FILTER",
+ [ 1, '>=', [ '', '' ], 1000, 0, undef, undef, [ [ 'F', '=', 0, 'k2_5' ] ] ]
+);
+
+# same as above
+exec_multi(
+ 4, "FILTER",
+ [ 1, '>=', [ '', '' ], 1000, 0, undef, undef, [ [ 'F', '=', 0, 'k2_5' ] ] ],
+);
+
+# select k1, k2, v1, v2 ... where (k1, k2) >= ('', '') and v1 = 3
+exec_multi(
+ 4, "FILTER",
+ [ 2, '>=', [ '', '' ], 1000, 0, undef, undef, [ [ 'F', '=', 2, 3 ] ] ],
+);
+
+# select k1, k2, v1, v2 ... where (k1, k2) >= ('k1_1', '') and k1 <= 'k1_2'
+exec_multi(
+ 4, "FILTER",
+ [ 2, '>=', [ 'k1_1', '' ], 1000, 0, undef, undef,
+ [ [ 'W', '<=', 0, 'k1_2' ] ] ],
+);
+
+# select k1, k2, v1, v2 ... where (k1, k2) >= ('k1_1', '') and k1 <= 'k1_2'
+# and v2 >= 10
+exec_multi(
+ 4, "FILTER",
+ [ 2, '>=', [ 'k1_1', '' ], 1000, 0, undef, undef,
+ [ [ 'W', '<=', 0, 'k1_2' ], [ 'F', '>=', 3, 10 ] ] ],
+);
+
+# update ... set v2 = -1 where (k1, k2) >= ('k1_3', '') and v2 = 10
+exec_multi(
+ 4, "FILTER",
+ [ 3, '>=', [ 'k1_1', '' ], 1000, 0, 'U', [ -1 ],
+ [ [ 'F', '=', 1, 10 ] ] ],
+);
+
+exec_multi(
+ 4, "VAL",
+ [ 1, '>=', [ '', '' ], 1000, 0 ],
+);
+# all
+
+exit 0;
+
+sub exec_single {
+ my ($width, $mess, $req) = @_;
+ print "$mess\n";
+ my $res = $hs->execute_single(@$req);
+ {
+ my $code = shift(@$res);
+ print "code=$code\n";
+ my $i = 0;
+ for my $fld (@$res) {
+ print "[$fld]";
+ if (++$i >= $width) {
+ print "\n";
+ $i = 0;
+ }
+ }
+ print "\n";
+ }
+}
+
+sub exec_multi {
+ my $width = shift(@_);
+ my $mess = shift(@_);
+ print "$mess\n";
+ my $mres = $hs->execute_multi(\@_);
+ for my $res (@$mres) {
+ my $code = shift(@$res);
+ print "code=$code\n";
+ my $i = 0;
+ for my $fld (@$res) {
+ print "[$fld]";
+ if (++$i >= $width) {
+ print "\n";
+ $i = 0;
+ }
+ }
+ print "\n";
+ }
+}
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test13.expected b/plugin/handler_socket/regtest/test_01_lib/test13.expected
new file mode 100644
index 00000000..3330382e
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test13.expected
@@ -0,0 +1,92 @@
+HSINSERT
+11 v1hs_0
+12 v1hs_1
+13 v1hs_2
+14 v1hs_3
+15 v1hs_4
+16 v1hs_5
+17 v1hs_6
+18 v1hs_7
+19 v1hs_8
+20 v1hs_9
+21 v1hs3_0
+22 v1hs3_0
+23 v1hs3_0
+24 v1hs3_1
+25 v1hs3_1
+26 v1hs3_1
+27 v1hs3_2
+28 v1hs3_2
+29 v1hs3_2
+30 v1hs3_3
+31 v1hs3_3
+32 v1hs3_3
+33 v1hs3_4
+34 v1hs3_4
+35 v1hs3_4
+36 v1hs3_5
+37 v1hs3_5
+38 v1hs3_5
+39 v1hs3_6
+40 v1hs3_6
+41 v1hs3_6
+42 v1hs3_7
+43 v1hs3_7
+44 v1hs3_7
+45 v1hs3_8
+46 v1hs3_8
+47 v1hs3_8
+48 v1hs3_9
+49 v1hs3_9
+50 v1hs3_9
+DUMP_TABLE
+1 v1sql_0 v2sql_0
+2 v1sql_1 v2sql_1
+3 v1sql_2 v2sql_2
+4 v1sql_3 v2sql_3
+5 v1sql_4 v2sql_4
+6 v1sql_5 v2sql_5
+7 v1sql_6 v2sql_6
+8 v1sql_7 v2sql_7
+9 v1sql_8 v2sql_8
+10 v1sql_9 v2sql_9
+11 v1hs_0 v2hs_0
+12 v1hs_1 v2hs_1
+13 v1hs_2 v2hs_2
+14 v1hs_3 v2hs_3
+15 v1hs_4 v2hs_4
+16 v1hs_5 v2hs_5
+17 v1hs_6 v2hs_6
+18 v1hs_7 v2hs_7
+19 v1hs_8 v2hs_8
+20 v1hs_9 v2hs_9
+21 v1hs3_0 v2hs3_0
+22 v1hs3_0 v2hs3_0
+23 v1hs3_0 v2hs3_0
+24 v1hs3_1 v2hs3_1
+25 v1hs3_1 v2hs3_1
+26 v1hs3_1 v2hs3_1
+27 v1hs3_2 v2hs3_2
+28 v1hs3_2 v2hs3_2
+29 v1hs3_2 v2hs3_2
+30 v1hs3_3 v2hs3_3
+31 v1hs3_3 v2hs3_3
+32 v1hs3_3 v2hs3_3
+33 v1hs3_4 v2hs3_4
+34 v1hs3_4 v2hs3_4
+35 v1hs3_4 v2hs3_4
+36 v1hs3_5 v2hs3_5
+37 v1hs3_5 v2hs3_5
+38 v1hs3_5 v2hs3_5
+39 v1hs3_6 v2hs3_6
+40 v1hs3_6 v2hs3_6
+41 v1hs3_6 v2hs3_6
+42 v1hs3_7 v2hs3_7
+43 v1hs3_7 v2hs3_7
+44 v1hs3_7 v2hs3_7
+45 v1hs3_8 v2hs3_8
+46 v1hs3_8 v2hs3_8
+47 v1hs3_8 v2hs3_8
+48 v1hs3_9 v2hs3_9
+49 v1hs3_9 v2hs3_9
+50 v1hs3_9 v2hs3_9
diff --git a/plugin/handler_socket/regtest/test_01_lib/test13.pl b/plugin/handler_socket/regtest/test_01_lib/test13.pl
new file mode 100644
index 00000000..2068c4bc
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test13.pl
@@ -0,0 +1,92 @@
+#!/usr/bin/env perl
+
+# vim:sw=2:ai
+
+# test for auto_increment
+
+BEGIN {
+ push @INC, "../common/";
+};
+
+use strict;
+use warnings;
+use hstest;
+
+my $dbh = hstest::init_testdb();
+my $table = 'hstesttbl';
+my $tablesize = 10;
+$dbh->do(
+ "create table $table (" .
+ "k int primary key auto_increment, " .
+ "v1 varchar(30), " .
+ "v2 varchar(30)) " .
+ "engine = myisam default charset = binary");
+srand(999);
+
+my $sth = $dbh->prepare("insert into $table values (?,?,?)");
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = 0;
+ my $v1 = "v1sql_" . $i;
+ my $v2 = "v2sql_" . $i;
+ $sth->execute($k, $v1, $v2);
+}
+
+my %valmap = ();
+
+print "HSINSERT\n";
+my $hs = hstest::get_hs_connection(undef, 9999);
+my $dbname = $hstest::conf{dbname};
+$hs->open_index(1, $dbname, $table, '', 'k,v1,v2');
+# inserts with auto_increment
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = 0;
+ my $v1 = "v1hs_" . $i;
+ my $v2 = "v2hs_" . $i;
+ my $r = $hs->execute_insert(1, [ $k, $v1, $v2 ]);
+ my $err = $r->[0];
+ if ($err != 0) {
+ my $err_str = $r->[1];
+ print "$err $err_str\n";
+ } else {
+ my $id = $r->[1];
+ print "$id $v1\n";
+ }
+}
+# make sure that it works even when inserts are pipelined. these requests
+# are possibly executed in a single transaction.
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = 0;
+ my $v1 = "v1hs3_" . $i;
+ my $v2 = "v2hs3_" . $i;
+ my $r = $hs->execute_multi([
+ [ 1, '+', [$k, $v1, $v2] ],
+ [ 1, '+', [$k, $v1, $v2] ],
+ [ 1, '+', [$k, $v1, $v2] ],
+ ]);
+ for (my $i = 0; $i < 3; ++$i) {
+ my $err = $r->[$i]->[0];
+ if ($err != 0) {
+ my $err_str = $r->[$i]->[1];
+ print "$err $err_str\n";
+ } else {
+ my $id = $r->[$i]->[1];
+ print "$id $v1\n";
+ }
+ }
+}
+undef $hs;
+
+dump_table();
+
+sub dump_table {
+ print "DUMP_TABLE\n";
+ my $aref = $dbh->selectall_arrayref("select k,v1,v2 from $table order by k");
+ for my $row (@$aref) {
+ my ($k, $v1, $v2) = @$row;
+ $v1 = "[null]" if !defined($v1);
+ $v2 = "[null]" if !defined($v2);
+ print "$k $v1 $v2\n";
+ # print "MISMATCH\n" if ($valmap{$k} ne $v);
+ }
+}
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test14.expected b/plugin/handler_socket/regtest/test_01_lib/test14.expected
new file mode 100644
index 00000000..00149dd9
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test14.expected
@@ -0,0 +1,144 @@
+DUMP_TABLE
+0
+1 0 A
+2 01 AB
+3 012 ABC
+4 0123 ABCD
+5 01234 ABCDE
+6 012345 ABCDEF
+7 0123456 ABCDEFG
+8 01234567 ABCDEFGH
+9 012345678 ABCDEFGHI
+10 0123456789 ABCDEFGHIJ
+11 01234567890 ABCDEFGHIJA
+12 012345678901 ABCDEFGHIJAB
+13 0123456789012 ABCDEFGHIJABC
+14 01234567890123 ABCDEFGHIJABCD
+15 012345678901234 ABCDEFGHIJABCDE
+16 0123456789012345 ABCDEFGHIJABCDEF
+17 01234567890123456 ABCDEFGHIJABCDEFG
+18 012345678901234567 ABCDEFGHIJABCDEFGH
+19 0123456789012345678 ABCDEFGHIJABCDEFGHI
+20 01234567890123456789 ABCDEFGHIJABCDEFGHIJ
+21 012345678901234567890 ABCDEFGHIJABCDEFGHIJA
+22 0123456789012345678901 ABCDEFGHIJABCDEFGHIJAB
+23 01234567890123456789012 ABCDEFGHIJABCDEFGHIJABC
+24 012345678901234567890123 ABCDEFGHIJABCDEFGHIJABCD
+25 0123456789012345678901234 ABCDEFGHIJABCDEFGHIJABCDE
+26 01234567890123456789012345 ABCDEFGHIJABCDEFGHIJABCDEF
+27 012345678901234567890123456 ABCDEFGHIJABCDEFGHIJABCDEFG
+28 0123456789012345678901234567 ABCDEFGHIJABCDEFGHIJABCDEFGH
+29 01234567890123456789012345678 ABCDEFGHIJABCDEFGHIJABCDEFGHI
+30 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ
+31 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ
+32 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ
+33 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ
+34 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ
+35 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ
+36 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ
+37 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ
+38 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ
+39 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ
+40 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ
+41 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ
+42 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ
+43 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ
+44 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ
+45 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ
+46 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ
+47 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ
+48 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ
+49 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ
+PK 0
+I1 0
+I2 0
+PK 1 0 A
+I1 1 0 A
+I2 1 0 A
+PK 2 01 AB
+I1 2 01 AB
+I2 2 01 AB
+PK 3 012 ABC
+I1 3 012 ABC
+I2 3 012 ABC
+PK 4 0123 ABCD
+I1 4 0123 ABCD
+I2 4 0123 ABCD
+PK 5 01234 ABCDE
+I1 5 01234 ABCDE
+I2 5 01234 ABCDE
+PK 6 012345 ABCDEF
+I1 6 012345 ABCDEF
+I2 6 012345 ABCDEF
+PK 7 0123456 ABCDEFG
+I1 7 0123456 ABCDEFG
+I2 7 0123456 ABCDEFG
+PK 8 01234567 ABCDEFGH
+I1 8 01234567 ABCDEFGH
+I2 8 01234567 ABCDEFGH
+PK 9 012345678 ABCDEFGHI
+I1 9 012345678 ABCDEFGHI
+I2 9 012345678 ABCDEFGHI
+PK 10 0123456789 ABCDEFGHIJ
+I1 10 0123456789 ABCDEFGHIJ
+I2 10 0123456789 ABCDEFGHIJ
+PK 11 01234567890 ABCDEFGHIJA
+I1 11 01234567890 ABCDEFGHIJA
+I2 11 01234567890 ABCDEFGHIJA
+PK 12 012345678901 ABCDEFGHIJAB
+I1 12 012345678901 ABCDEFGHIJAB
+I2 12 012345678901 ABCDEFGHIJAB
+PK 13 0123456789012 ABCDEFGHIJABC
+I1 13 0123456789012 ABCDEFGHIJABC
+I2 13 0123456789012 ABCDEFGHIJABC
+PK 14 01234567890123 ABCDEFGHIJABCD
+I1 14 01234567890123 ABCDEFGHIJABCD
+I2 14 01234567890123 ABCDEFGHIJABCD
+PK 15 012345678901234 ABCDEFGHIJABCDE
+I1 15 012345678901234 ABCDEFGHIJABCDE
+I2 15 012345678901234 ABCDEFGHIJABCDE
+PK 16 0123456789012345 ABCDEFGHIJABCDEF
+I1 16 0123456789012345 ABCDEFGHIJABCDEF
+I2 16 0123456789012345 ABCDEFGHIJABCDEF
+PK 17 01234567890123456 ABCDEFGHIJABCDEFG
+I1 17 01234567890123456 ABCDEFGHIJABCDEFG
+I2 17 01234567890123456 ABCDEFGHIJABCDEFG
+PK 18 012345678901234567 ABCDEFGHIJABCDEFGH
+I1 18 012345678901234567 ABCDEFGHIJABCDEFGH
+I2 18 012345678901234567 ABCDEFGHIJABCDEFGH
+PK 19 0123456789012345678 ABCDEFGHIJABCDEFGHI
+I1 19 0123456789012345678 ABCDEFGHIJABCDEFGHI
+I2 19 0123456789012345678 ABCDEFGHIJABCDEFGHI
+PK 20 01234567890123456789 ABCDEFGHIJABCDEFGHIJ
+I1 20 01234567890123456789 ABCDEFGHIJABCDEFGHIJ
+I2 20 01234567890123456789 ABCDEFGHIJABCDEFGHIJ
+PK 21 012345678901234567890 ABCDEFGHIJABCDEFGHIJA
+I1 21 012345678901234567890 ABCDEFGHIJABCDEFGHIJA
+I2 21 012345678901234567890 ABCDEFGHIJABCDEFGHIJA
+PK 22 0123456789012345678901 ABCDEFGHIJABCDEFGHIJAB
+I1 22 0123456789012345678901 ABCDEFGHIJABCDEFGHIJAB
+I2 22 0123456789012345678901 ABCDEFGHIJABCDEFGHIJAB
+PK 23 01234567890123456789012 ABCDEFGHIJABCDEFGHIJABC
+I1 23 01234567890123456789012 ABCDEFGHIJABCDEFGHIJABC
+I2 23 01234567890123456789012 ABCDEFGHIJABCDEFGHIJABC
+PK 24 012345678901234567890123 ABCDEFGHIJABCDEFGHIJABCD
+I1 24 012345678901234567890123 ABCDEFGHIJABCDEFGHIJABCD
+I2 24 012345678901234567890123 ABCDEFGHIJABCDEFGHIJABCD
+PK 25 0123456789012345678901234 ABCDEFGHIJABCDEFGHIJABCDE
+I1 25 0123456789012345678901234 ABCDEFGHIJABCDEFGHIJABCDE
+I2 25 0123456789012345678901234 ABCDEFGHIJABCDEFGHIJABCDE
+PK 26 01234567890123456789012345 ABCDEFGHIJABCDEFGHIJABCDEF
+I1 26 01234567890123456789012345 ABCDEFGHIJABCDEFGHIJABCDEF
+I2 26 01234567890123456789012345 ABCDEFGHIJABCDEFGHIJABCDEF
+PK 27 012345678901234567890123456 ABCDEFGHIJABCDEFGHIJABCDEFG
+I1 27 012345678901234567890123456 ABCDEFGHIJABCDEFGHIJABCDEFG
+I2 27 012345678901234567890123456 ABCDEFGHIJABCDEFGHIJABCDEFG
+PK 28 0123456789012345678901234567 ABCDEFGHIJABCDEFGHIJABCDEFGH
+I1 28 0123456789012345678901234567 ABCDEFGHIJABCDEFGHIJABCDEFGH
+I2 28 0123456789012345678901234567 ABCDEFGHIJABCDEFGHIJABCDEFGH
+PK 29 01234567890123456789012345678 ABCDEFGHIJABCDEFGHIJABCDEFGHI
+I1 29 01234567890123456789012345678 ABCDEFGHIJABCDEFGHIJABCDEFGHI
+I2 29 01234567890123456789012345678 ABCDEFGHIJABCDEFGHIJABCDEFGHI
+PK 30 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ
+I1 30 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ
+I2 30 012345678901234567890123456789 ABCDEFGHIJABCDEFGHIJABCDEFGHIJ
diff --git a/plugin/handler_socket/regtest/test_01_lib/test14.pl b/plugin/handler_socket/regtest/test_01_lib/test14.pl
new file mode 100644
index 00000000..ab890733
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test14.pl
@@ -0,0 +1,80 @@
+#!/usr/bin/env perl
+
+# vim:sw=2:ai
+
+# test for bugfix: commit/c88efe637f6a184b55d2bd8d060bda3e556572d8
+# (some trailing bytes were dropped for varlen or nullable key fields)
+
+BEGIN {
+ push @INC, "../common/";
+};
+
+use strict;
+use warnings;
+use hstest;
+
+my $dbh = hstest::init_testdb();
+my $table = 'hstesttbl';
+my $tablesize = 50;
+$dbh->do(
+ "create table $table (" .
+ "k int primary key, " .
+ "v1 varchar(30), " .
+ "v2 varchar(30), " .
+ "index i1(v1), index i2(v2, v1)) " .
+ "engine = myisam default charset = binary");
+srand(999);
+
+my %valmap = ();
+
+my $sth = $dbh->prepare("insert ignore into $table values (?,?,?)");
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = $i;
+ my ($s1, $s2) = ("", "");
+ for (my $j = 0; $j < $i; ++$j) {
+ $s1 .= chr(48 + $j % 10);
+ $s2 .= chr(65 + $j % 10);
+ }
+ my $v1 = $s1;
+ my $v2 = $s2;
+ $sth->execute($k, $v1, $v2);
+ $valmap{$k} = [ $v1, $v2 ];
+}
+
+dump_table();
+
+my $hs = hstest::get_hs_connection(undef, 9999);
+my $dbname = $hstest::conf{dbname};
+$hs->open_index(1, $dbname, $table, '', 'k,v1,v2');
+$hs->open_index(2, $dbname, $table, 'i1', 'k,v1,v2');
+$hs->open_index(3, $dbname, $table, 'i2', 'k,v1,v2');
+
+for (my $i = 0; $i <= 30; ++$i) {
+ my ($v1, $v2) = @{$valmap{$i}};
+ my ($rk, $rv1, $rv2);
+ my $r = $hs->execute_single(1, '=', [ $i ], 1, 0);
+ shift(@$r);
+ ($rk, $rv1, $rv2) = @$r;
+ print "PK $rk $rv1 $rv2\n";
+ $r = $hs->execute_single(2, '=', [ $v1 ], 1, 0);
+ shift(@$r);
+ ($rk, $rv1, $rv2) = @$r;
+ print "I1 $rk $rv1 $rv2\n";
+ $r = $hs->execute_single(3, '=', [ $v2, $v1 ], 1, 0);
+ shift(@$r);
+ ($rk, $rv1, $rv2) = @$r;
+ print "I2 $rk $rv1 $rv2\n";
+}
+
+sub dump_table {
+ print "DUMP_TABLE\n";
+ my $aref = $dbh->selectall_arrayref("select k,v1,v2 from $table order by k");
+ for my $row (@$aref) {
+ my ($k, $v1, $v2) = @$row;
+ $v1 = "[null]" if !defined($v1);
+ $v2 = "[null]" if !defined($v2);
+ print "$k $v1 $v2\n";
+ # print "MISMATCH\n" if ($valmap{$k} ne $v);
+ }
+}
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test15.expected b/plugin/handler_socket/regtest/test_01_lib/test15.expected
new file mode 100644
index 00000000..ea15afef
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test15.expected
@@ -0,0 +1,764 @@
+TYPE TINYINT
+DUMP_TABLE_BEGIN
+-128 s-128 -128
+-42 s-42 -42
+-14 s-14 -14
+-4 s-4 -4
+-1 s-1 -1
+0 s0 0
+1 s1 1
+4 s4 4
+14 s14 14
+42 s42 42
+127 s127 127
+DUMP_TABLE_END
+PK[-128] -128 s-128 -128
+I1[s-128] -128 s-128 -128
+I2[-128, s-128] -128 s-128 -128
+I2p[-128] -128 s-128 -128
+PK[-42] -42 s-42 -42
+I1[s-42] -42 s-42 -42
+I2[-42, s-42] -42 s-42 -42
+I2p[-42] -42 s-42 -42
+PK[-14] -14 s-14 -14
+I1[s-14] -14 s-14 -14
+I2[-14, s-14] -14 s-14 -14
+I2p[-14] -14 s-14 -14
+PK[-4] -4 s-4 -4
+I1[s-4] -4 s-4 -4
+I2[-4, s-4] -4 s-4 -4
+I2p[-4] -4 s-4 -4
+PK[-1] -1 s-1 -1
+I1[s-1] -1 s-1 -1
+I2[-1, s-1] -1 s-1 -1
+I2p[-1] -1 s-1 -1
+PK[-1] -1 s-1 -1
+I1[s-1] -1 s-1 -1
+I2[-1, s-1] -1 s-1 -1
+I2p[-1] -1 s-1 -1
+PK[0] 0 s0 0
+I1[s0] 0 s0 0
+I2[0, s0] 0 s0 0
+I2p[0] 0 s0 0
+PK[0] 0 s0 0
+I1[s0] 0 s0 0
+I2[0, s0] 0 s0 0
+I2p[0] 0 s0 0
+PK[1] 1 s1 1
+I1[s1] 1 s1 1
+I2[1, s1] 1 s1 1
+I2p[1] 1 s1 1
+PK[1] 1 s1 1
+I1[s1] 1 s1 1
+I2[1, s1] 1 s1 1
+I2p[1] 1 s1 1
+PK[4] 4 s4 4
+I1[s4] 4 s4 4
+I2[4, s4] 4 s4 4
+I2p[4] 4 s4 4
+PK[14] 14 s14 14
+I1[s14] 14 s14 14
+I2[14, s14] 14 s14 14
+I2p[14] 14 s14 14
+PK[42] 42 s42 42
+I1[s42] 42 s42 42
+I2[42, s42] 42 s42 42
+I2p[42] 42 s42 42
+PK[127] 127 s127 127
+I1[s127] 127 s127 127
+I2[127, s127] 127 s127 127
+I2p[127] 127 s127 127
+
+TYPE TINYINT UNSIGNED
+DUMP_TABLE_BEGIN
+0 s0 0
+1 s1 1
+3 s3 3
+9 s9 9
+28 s28 28
+85 s85 85
+255 s255 255
+DUMP_TABLE_END
+PK[0] 0 s0 0
+I1[s0] 0 s0 0
+I2[0, s0] 0 s0 0
+I2p[0] 0 s0 0
+PK[1] 1 s1 1
+I1[s1] 1 s1 1
+I2[1, s1] 1 s1 1
+I2p[1] 1 s1 1
+PK[1] 1 s1 1
+I1[s1] 1 s1 1
+I2[1, s1] 1 s1 1
+I2p[1] 1 s1 1
+PK[3] 3 s3 3
+I1[s3] 3 s3 3
+I2[3, s3] 3 s3 3
+I2p[3] 3 s3 3
+PK[9] 9 s9 9
+I1[s9] 9 s9 9
+I2[9, s9] 9 s9 9
+I2p[9] 9 s9 9
+PK[28] 28 s28 28
+I1[s28] 28 s28 28
+I2[28, s28] 28 s28 28
+I2p[28] 28 s28 28
+PK[85] 85 s85 85
+I1[s85] 85 s85 85
+I2[85, s85] 85 s85 85
+I2p[85] 85 s85 85
+PK[255] 255 s255 255
+I1[s255] 255 s255 255
+I2[255, s255] 255 s255 255
+I2p[255] 255 s255 255
+
+TYPE SMALLINT
+DUMP_TABLE_BEGIN
+-32768 s-32768 -32768
+-10922 s-10922 -10922
+-3640 s-3640 -3640
+-1213 s-1213 -1213
+-404 s-404 -404
+-134 s-134 -134
+-1 s-1 -1
+0 s0 0
+1 s1 1
+134 s134 134
+404 s404 404
+1213 s1213 1213
+3640 s3640 3640
+10922 s10922 10922
+32767 s32768 32767
+DUMP_TABLE_END
+PK[-32768] -32768 s-32768 -32768
+I1[s-32768] -32768 s-32768 -32768
+I2[-32768, s-32768] -32768 s-32768 -32768
+I2p[-32768] -32768 s-32768 -32768
+PK[-10922] -10922 s-10922 -10922
+I1[s-10922] -10922 s-10922 -10922
+I2[-10922, s-10922] -10922 s-10922 -10922
+I2p[-10922] -10922 s-10922 -10922
+PK[-3640] -3640 s-3640 -3640
+I1[s-3640] -3640 s-3640 -3640
+I2[-3640, s-3640] -3640 s-3640 -3640
+I2p[-3640] -3640 s-3640 -3640
+PK[-1213] -1213 s-1213 -1213
+I1[s-1213] -1213 s-1213 -1213
+I2[-1213, s-1213] -1213 s-1213 -1213
+I2p[-1213] -1213 s-1213 -1213
+PK[-404] -404 s-404 -404
+I1[s-404] -404 s-404 -404
+I2[-404, s-404] -404 s-404 -404
+I2p[-404] -404 s-404 -404
+PK[-134] -134 s-134 -134
+I1[s-134] -134 s-134 -134
+I2[-134, s-134] -134 s-134 -134
+I2p[-134] -134 s-134 -134
+PK[-1] -1 s-1 -1
+I1[s-1] -1 s-1 -1
+I2[-1, s-1] -1 s-1 -1
+I2p[-1] -1 s-1 -1
+PK[0] 0 s0 0
+I1[s0] 0 s0 0
+I2[0, s0] 0 s0 0
+I2p[0] 0 s0 0
+PK[1] 1 s1 1
+I1[s1] 1 s1 1
+I2[1, s1] 1 s1 1
+I2p[1] 1 s1 1
+PK[134] 134 s134 134
+I1[s134] 134 s134 134
+I2[134, s134] 134 s134 134
+I2p[134] 134 s134 134
+PK[404] 404 s404 404
+I1[s404] 404 s404 404
+I2[404, s404] 404 s404 404
+I2p[404] 404 s404 404
+PK[1213] 1213 s1213 1213
+I1[s1213] 1213 s1213 1213
+I2[1213, s1213] 1213 s1213 1213
+I2p[1213] 1213 s1213 1213
+PK[3640] 3640 s3640 3640
+I1[s3640] 3640 s3640 3640
+I2[3640, s3640] 3640 s3640 3640
+I2p[3640] 3640 s3640 3640
+PK[10922] 10922 s10922 10922
+I1[s10922] 10922 s10922 10922
+I2[10922, s10922] 10922 s10922 10922
+I2p[10922] 10922 s10922 10922
+PK[32768] 32767 s32768 32767
+I1[s32768] 32767 s32768 32767
+I2[32768, s32768] 32767 s32768 32767
+I2p[32768] 32767 s32768 32767
+
+TYPE SMALLINT UNSIGNED
+DUMP_TABLE_BEGIN
+0 s0 0
+1 s1 1
+269 s269 269
+809 s809 809
+2427 s2427 2427
+7281 s7281 7281
+21845 s21845 21845
+65535 s65535 65535
+DUMP_TABLE_END
+PK[0] 0 s0 0
+I1[s0] 0 s0 0
+I2[0, s0] 0 s0 0
+I2p[0] 0 s0 0
+PK[1] 1 s1 1
+I1[s1] 1 s1 1
+I2[1, s1] 1 s1 1
+I2p[1] 1 s1 1
+PK[269] 269 s269 269
+I1[s269] 269 s269 269
+I2[269, s269] 269 s269 269
+I2p[269] 269 s269 269
+PK[809] 809 s809 809
+I1[s809] 809 s809 809
+I2[809, s809] 809 s809 809
+I2p[809] 809 s809 809
+PK[2427] 2427 s2427 2427
+I1[s2427] 2427 s2427 2427
+I2[2427, s2427] 2427 s2427 2427
+I2p[2427] 2427 s2427 2427
+PK[7281] 7281 s7281 7281
+I1[s7281] 7281 s7281 7281
+I2[7281, s7281] 7281 s7281 7281
+I2p[7281] 7281 s7281 7281
+PK[21845] 21845 s21845 21845
+I1[s21845] 21845 s21845 21845
+I2[21845, s21845] 21845 s21845 21845
+I2p[21845] 21845 s21845 21845
+PK[65535] 65535 s65535 65535
+I1[s65535] 65535 s65535 65535
+I2[65535, s65535] 65535 s65535 65535
+I2p[65535] 65535 s65535 65535
+
+TYPE MEDIUMINT
+DUMP_TABLE_BEGIN
+-8388608 s-8388608 -8388608
+-2796202 s-2796202 -2796202
+-932067 s-932067 -932067
+-310689 s-310689 -310689
+-103563 s-103563 -103563
+-34521 s-34521 -34521
+-1 s-1 -1
+0 s0 0
+1 s1 1
+34521 s34521 34521
+103563 s103563 103563
+310689 s310689 310689
+932067 s932067 932067
+2796202 s2796202 2796202
+8388607 s8388607 8388607
+DUMP_TABLE_END
+PK[-8388608] -8388608 s-8388608 -8388608
+I1[s-8388608] -8388608 s-8388608 -8388608
+I2[-8388608, s-8388608] -8388608 s-8388608 -8388608
+I2p[-8388608] -8388608 s-8388608 -8388608
+PK[-2796202] -2796202 s-2796202 -2796202
+I1[s-2796202] -2796202 s-2796202 -2796202
+I2[-2796202, s-2796202] -2796202 s-2796202 -2796202
+I2p[-2796202] -2796202 s-2796202 -2796202
+PK[-932067] -932067 s-932067 -932067
+I1[s-932067] -932067 s-932067 -932067
+I2[-932067, s-932067] -932067 s-932067 -932067
+I2p[-932067] -932067 s-932067 -932067
+PK[-310689] -310689 s-310689 -310689
+I1[s-310689] -310689 s-310689 -310689
+I2[-310689, s-310689] -310689 s-310689 -310689
+I2p[-310689] -310689 s-310689 -310689
+PK[-103563] -103563 s-103563 -103563
+I1[s-103563] -103563 s-103563 -103563
+I2[-103563, s-103563] -103563 s-103563 -103563
+I2p[-103563] -103563 s-103563 -103563
+PK[-34521] -34521 s-34521 -34521
+I1[s-34521] -34521 s-34521 -34521
+I2[-34521, s-34521] -34521 s-34521 -34521
+I2p[-34521] -34521 s-34521 -34521
+PK[-1] -1 s-1 -1
+I1[s-1] -1 s-1 -1
+I2[-1, s-1] -1 s-1 -1
+I2p[-1] -1 s-1 -1
+PK[0] 0 s0 0
+I1[s0] 0 s0 0
+I2[0, s0] 0 s0 0
+I2p[0] 0 s0 0
+PK[1] 1 s1 1
+I1[s1] 1 s1 1
+I2[1, s1] 1 s1 1
+I2p[1] 1 s1 1
+PK[34521] 34521 s34521 34521
+I1[s34521] 34521 s34521 34521
+I2[34521, s34521] 34521 s34521 34521
+I2p[34521] 34521 s34521 34521
+PK[103563] 103563 s103563 103563
+I1[s103563] 103563 s103563 103563
+I2[103563, s103563] 103563 s103563 103563
+I2p[103563] 103563 s103563 103563
+PK[310689] 310689 s310689 310689
+I1[s310689] 310689 s310689 310689
+I2[310689, s310689] 310689 s310689 310689
+I2p[310689] 310689 s310689 310689
+PK[932067] 932067 s932067 932067
+I1[s932067] 932067 s932067 932067
+I2[932067, s932067] 932067 s932067 932067
+I2p[932067] 932067 s932067 932067
+PK[2796202] 2796202 s2796202 2796202
+I1[s2796202] 2796202 s2796202 2796202
+I2[2796202, s2796202] 2796202 s2796202 2796202
+I2p[2796202] 2796202 s2796202 2796202
+PK[8388607] 8388607 s8388607 8388607
+I1[s8388607] 8388607 s8388607 8388607
+I2[8388607, s8388607] 8388607 s8388607 8388607
+I2p[8388607] 8388607 s8388607 8388607
+
+TYPE MEDIUMINT UNSIGNED
+DUMP_TABLE_BEGIN
+0 s0 0
+1 s1 1
+69042 s69042 69042
+207126 s207126 207126
+621378 s621378 621378
+1864135 s1864135 1864135
+5592405 s5592405 5592405
+16777215 s16777215 16777215
+DUMP_TABLE_END
+PK[0] 0 s0 0
+I1[s0] 0 s0 0
+I2[0, s0] 0 s0 0
+I2p[0] 0 s0 0
+PK[1] 1 s1 1
+I1[s1] 1 s1 1
+I2[1, s1] 1 s1 1
+I2p[1] 1 s1 1
+PK[69042] 69042 s69042 69042
+I1[s69042] 69042 s69042 69042
+I2[69042, s69042] 69042 s69042 69042
+I2p[69042] 69042 s69042 69042
+PK[207126] 207126 s207126 207126
+I1[s207126] 207126 s207126 207126
+I2[207126, s207126] 207126 s207126 207126
+I2p[207126] 207126 s207126 207126
+PK[621378] 621378 s621378 621378
+I1[s621378] 621378 s621378 621378
+I2[621378, s621378] 621378 s621378 621378
+I2p[621378] 621378 s621378 621378
+PK[1864135] 1864135 s1864135 1864135
+I1[s1864135] 1864135 s1864135 1864135
+I2[1864135, s1864135] 1864135 s1864135 1864135
+I2p[1864135] 1864135 s1864135 1864135
+PK[5592405] 5592405 s5592405 5592405
+I1[s5592405] 5592405 s5592405 5592405
+I2[5592405, s5592405] 5592405 s5592405 5592405
+I2p[5592405] 5592405 s5592405 5592405
+PK[16777215] 16777215 s16777215 16777215
+I1[s16777215] 16777215 s16777215 16777215
+I2[16777215, s16777215] 16777215 s16777215 16777215
+I2p[16777215] 16777215 s16777215 16777215
+
+TYPE INT
+DUMP_TABLE_BEGIN
+-2147483648 s-2147483648 -2147483648
+-715827882 s-715827882 -715827882
+-238609294 s-238609294 -238609294
+-79536431 s-79536431 -79536431
+-26512143 s-26512143 -26512143
+-8837381 s-8837381 -8837381
+-1 s-1 -1
+0 s0 0
+1 s1 1
+8837381 s8837381 8837381
+26512143 s26512143 26512143
+79536431 s79536431 79536431
+238609294 s238609294 238609294
+715827882 s715827882 715827882
+2147483647 s2147483647 2147483647
+DUMP_TABLE_END
+PK[-2147483648] -2147483648 s-2147483648 -2147483648
+I1[s-2147483648] -2147483648 s-2147483648 -2147483648
+I2[-2147483648, s-2147483648] -2147483648 s-2147483648 -2147483648
+I2p[-2147483648] -2147483648 s-2147483648 -2147483648
+PK[-715827882] -715827882 s-715827882 -715827882
+I1[s-715827882] -715827882 s-715827882 -715827882
+I2[-715827882, s-715827882] -715827882 s-715827882 -715827882
+I2p[-715827882] -715827882 s-715827882 -715827882
+PK[-238609294] -238609294 s-238609294 -238609294
+I1[s-238609294] -238609294 s-238609294 -238609294
+I2[-238609294, s-238609294] -238609294 s-238609294 -238609294
+I2p[-238609294] -238609294 s-238609294 -238609294
+PK[-79536431] -79536431 s-79536431 -79536431
+I1[s-79536431] -79536431 s-79536431 -79536431
+I2[-79536431, s-79536431] -79536431 s-79536431 -79536431
+I2p[-79536431] -79536431 s-79536431 -79536431
+PK[-26512143] -26512143 s-26512143 -26512143
+I1[s-26512143] -26512143 s-26512143 -26512143
+I2[-26512143, s-26512143] -26512143 s-26512143 -26512143
+I2p[-26512143] -26512143 s-26512143 -26512143
+PK[-8837381] -8837381 s-8837381 -8837381
+I1[s-8837381] -8837381 s-8837381 -8837381
+I2[-8837381, s-8837381] -8837381 s-8837381 -8837381
+I2p[-8837381] -8837381 s-8837381 -8837381
+PK[-1] -1 s-1 -1
+I1[s-1] -1 s-1 -1
+I2[-1, s-1] -1 s-1 -1
+I2p[-1] -1 s-1 -1
+PK[0] 0 s0 0
+I1[s0] 0 s0 0
+I2[0, s0] 0 s0 0
+I2p[0] 0 s0 0
+PK[1] 1 s1 1
+I1[s1] 1 s1 1
+I2[1, s1] 1 s1 1
+I2p[1] 1 s1 1
+PK[8837381] 8837381 s8837381 8837381
+I1[s8837381] 8837381 s8837381 8837381
+I2[8837381, s8837381] 8837381 s8837381 8837381
+I2p[8837381] 8837381 s8837381 8837381
+PK[26512143] 26512143 s26512143 26512143
+I1[s26512143] 26512143 s26512143 26512143
+I2[26512143, s26512143] 26512143 s26512143 26512143
+I2p[26512143] 26512143 s26512143 26512143
+PK[79536431] 79536431 s79536431 79536431
+I1[s79536431] 79536431 s79536431 79536431
+I2[79536431, s79536431] 79536431 s79536431 79536431
+I2p[79536431] 79536431 s79536431 79536431
+PK[238609294] 238609294 s238609294 238609294
+I1[s238609294] 238609294 s238609294 238609294
+I2[238609294, s238609294] 238609294 s238609294 238609294
+I2p[238609294] 238609294 s238609294 238609294
+PK[715827882] 715827882 s715827882 715827882
+I1[s715827882] 715827882 s715827882 715827882
+I2[715827882, s715827882] 715827882 s715827882 715827882
+I2p[715827882] 715827882 s715827882 715827882
+PK[2147483647] 2147483647 s2147483647 2147483647
+I1[s2147483647] 2147483647 s2147483647 2147483647
+I2[2147483647, s2147483647] 2147483647 s2147483647 2147483647
+I2p[2147483647] 2147483647 s2147483647 2147483647
+
+TYPE INT UNSIGNED
+DUMP_TABLE_BEGIN
+0 s0 0
+1 s1 1
+17674762 s17674762 17674762
+53024287 s53024287 53024287
+159072862 s159072862 159072862
+477218588 s477218588 477218588
+1431655765 s1431655765 1431655765
+4294967295 s4294967295 4294967295
+DUMP_TABLE_END
+PK[0] 0 s0 0
+I1[s0] 0 s0 0
+I2[0, s0] 0 s0 0
+I2p[0] 0 s0 0
+PK[1] 1 s1 1
+I1[s1] 1 s1 1
+I2[1, s1] 1 s1 1
+I2p[1] 1 s1 1
+PK[17674762] 17674762 s17674762 17674762
+I1[s17674762] 17674762 s17674762 17674762
+I2[17674762, s17674762] 17674762 s17674762 17674762
+I2p[17674762] 17674762 s17674762 17674762
+PK[53024287] 53024287 s53024287 53024287
+I1[s53024287] 53024287 s53024287 53024287
+I2[53024287, s53024287] 53024287 s53024287 53024287
+I2p[53024287] 53024287 s53024287 53024287
+PK[159072862] 159072862 s159072862 159072862
+I1[s159072862] 159072862 s159072862 159072862
+I2[159072862, s159072862] 159072862 s159072862 159072862
+I2p[159072862] 159072862 s159072862 159072862
+PK[477218588] 477218588 s477218588 477218588
+I1[s477218588] 477218588 s477218588 477218588
+I2[477218588, s477218588] 477218588 s477218588 477218588
+I2p[477218588] 477218588 s477218588 477218588
+PK[1431655765] 1431655765 s1431655765 1431655765
+I1[s1431655765] 1431655765 s1431655765 1431655765
+I2[1431655765, s1431655765] 1431655765 s1431655765 1431655765
+I2p[1431655765] 1431655765 s1431655765 1431655765
+PK[4294967295] 4294967295 s4294967295 4294967295
+I1[s4294967295] 4294967295 s4294967295 4294967295
+I2[4294967295, s4294967295] 4294967295 s4294967295 4294967295
+I2p[4294967295] 4294967295 s4294967295 4294967295
+
+TYPE BIGINT
+DUMP_TABLE_BEGIN
+-9223372036854775808 s-9223372036854775808 -9223372036854775808
+-3074457345618258602 s-3074457345618258602 -3074457345618258602
+-1024819115206086200 s-1024819115206086200 -1024819115206086200
+-341606371735362066 s-341606371735362066 -341606371735362066
+-113868790578454022 s-113868790578454022 -113868790578454022
+-37956263526151340 s-37956263526151340 -37956263526151340
+-1 s-1 -1
+0 s0 0
+1 s1 1
+37956263526151340 s37956263526151340 37956263526151340
+113868790578454022 s113868790578454022 113868790578454022
+341606371735362066 s341606371735362066 341606371735362066
+1024819115206086200 s1024819115206086200 1024819115206086200
+3074457345618258602 s3074457345618258602 3074457345618258602
+9223372036854775807 s9223372036854775807 9223372036854775807
+DUMP_TABLE_END
+PK[-9223372036854775808] -9223372036854775808 s-9223372036854775808 -9223372036854775808
+I1[s-9223372036854775808] -9223372036854775808 s-9223372036854775808 -9223372036854775808
+I2[-9223372036854775808, s-9223372036854775808] -9223372036854775808 s-9223372036854775808 -9223372036854775808
+I2p[-9223372036854775808] -9223372036854775808 s-9223372036854775808 -9223372036854775808
+PK[-3074457345618258602] -3074457345618258602 s-3074457345618258602 -3074457345618258602
+I1[s-3074457345618258602] -3074457345618258602 s-3074457345618258602 -3074457345618258602
+I2[-3074457345618258602, s-3074457345618258602] -3074457345618258602 s-3074457345618258602 -3074457345618258602
+I2p[-3074457345618258602] -3074457345618258602 s-3074457345618258602 -3074457345618258602
+PK[-1024819115206086200] -1024819115206086200 s-1024819115206086200 -1024819115206086200
+I1[s-1024819115206086200] -1024819115206086200 s-1024819115206086200 -1024819115206086200
+I2[-1024819115206086200, s-1024819115206086200] -1024819115206086200 s-1024819115206086200 -1024819115206086200
+I2p[-1024819115206086200] -1024819115206086200 s-1024819115206086200 -1024819115206086200
+PK[-341606371735362066] -341606371735362066 s-341606371735362066 -341606371735362066
+I1[s-341606371735362066] -341606371735362066 s-341606371735362066 -341606371735362066
+I2[-341606371735362066, s-341606371735362066] -341606371735362066 s-341606371735362066 -341606371735362066
+I2p[-341606371735362066] -341606371735362066 s-341606371735362066 -341606371735362066
+PK[-113868790578454022] -113868790578454022 s-113868790578454022 -113868790578454022
+I1[s-113868790578454022] -113868790578454022 s-113868790578454022 -113868790578454022
+I2[-113868790578454022, s-113868790578454022] -113868790578454022 s-113868790578454022 -113868790578454022
+I2p[-113868790578454022] -113868790578454022 s-113868790578454022 -113868790578454022
+PK[-37956263526151340] -37956263526151340 s-37956263526151340 -37956263526151340
+I1[s-37956263526151340] -37956263526151340 s-37956263526151340 -37956263526151340
+I2[-37956263526151340, s-37956263526151340] -37956263526151340 s-37956263526151340 -37956263526151340
+I2p[-37956263526151340] -37956263526151340 s-37956263526151340 -37956263526151340
+PK[-1] -1 s-1 -1
+I1[s-1] -1 s-1 -1
+I2[-1, s-1] -1 s-1 -1
+I2p[-1] -1 s-1 -1
+PK[0] 0 s0 0
+I1[s0] 0 s0 0
+I2[0, s0] 0 s0 0
+I2p[0] 0 s0 0
+PK[1] 1 s1 1
+I1[s1] 1 s1 1
+I2[1, s1] 1 s1 1
+I2p[1] 1 s1 1
+PK[37956263526151340] 37956263526151340 s37956263526151340 37956263526151340
+I1[s37956263526151340] 37956263526151340 s37956263526151340 37956263526151340
+I2[37956263526151340, s37956263526151340] 37956263526151340 s37956263526151340 37956263526151340
+I2p[37956263526151340] 37956263526151340 s37956263526151340 37956263526151340
+PK[113868790578454022] 113868790578454022 s113868790578454022 113868790578454022
+I1[s113868790578454022] 113868790578454022 s113868790578454022 113868790578454022
+I2[113868790578454022, s113868790578454022] 113868790578454022 s113868790578454022 113868790578454022
+I2p[113868790578454022] 113868790578454022 s113868790578454022 113868790578454022
+PK[341606371735362066] 341606371735362066 s341606371735362066 341606371735362066
+I1[s341606371735362066] 341606371735362066 s341606371735362066 341606371735362066
+I2[341606371735362066, s341606371735362066] 341606371735362066 s341606371735362066 341606371735362066
+I2p[341606371735362066] 341606371735362066 s341606371735362066 341606371735362066
+PK[1024819115206086200] 1024819115206086200 s1024819115206086200 1024819115206086200
+I1[s1024819115206086200] 1024819115206086200 s1024819115206086200 1024819115206086200
+I2[1024819115206086200, s1024819115206086200] 1024819115206086200 s1024819115206086200 1024819115206086200
+I2p[1024819115206086200] 1024819115206086200 s1024819115206086200 1024819115206086200
+PK[3074457345618258602] 3074457345618258602 s3074457345618258602 3074457345618258602
+I1[s3074457345618258602] 3074457345618258602 s3074457345618258602 3074457345618258602
+I2[3074457345618258602, s3074457345618258602] 3074457345618258602 s3074457345618258602 3074457345618258602
+I2p[3074457345618258602] 3074457345618258602 s3074457345618258602 3074457345618258602
+PK[9223372036854775807] 9223372036854775807 s9223372036854775807 9223372036854775807
+I1[s9223372036854775807] 9223372036854775807 s9223372036854775807 9223372036854775807
+I2[9223372036854775807, s9223372036854775807] 9223372036854775807 s9223372036854775807 9223372036854775807
+I2p[9223372036854775807] 9223372036854775807 s9223372036854775807 9223372036854775807
+
+TYPE BIGINT UNSIGNED
+DUMP_TABLE_BEGIN
+0 s0 0
+1 s1 1
+75912527052302681 s75912527052302681 75912527052302681
+227737581156908044 s227737581156908044 227737581156908044
+683212743470724133 s683212743470724133 683212743470724133
+2049638230412172401 s2049638230412172401 2049638230412172401
+6148914691236517205 s6148914691236517205 6148914691236517205
+18446744073709551615 s18446744073709551615 18446744073709551615
+DUMP_TABLE_END
+PK[0] 0 s0 0
+I1[s0] 0 s0 0
+I2[0, s0] 0 s0 0
+I2p[0] 0 s0 0
+PK[1] 1 s1 1
+I1[s1] 1 s1 1
+I2[1, s1] 1 s1 1
+I2p[1] 1 s1 1
+PK[75912527052302681] 75912527052302681 s75912527052302681 75912527052302681
+I1[s75912527052302681] 75912527052302681 s75912527052302681 75912527052302681
+I2[75912527052302681, s75912527052302681] 75912527052302681 s75912527052302681 75912527052302681
+I2p[75912527052302681] 75912527052302681 s75912527052302681 75912527052302681
+PK[227737581156908044] 227737581156908044 s227737581156908044 227737581156908044
+I1[s227737581156908044] 227737581156908044 s227737581156908044 227737581156908044
+I2[227737581156908044, s227737581156908044] 227737581156908044 s227737581156908044 227737581156908044
+I2p[227737581156908044] 227737581156908044 s227737581156908044 227737581156908044
+PK[683212743470724133] 683212743470724133 s683212743470724133 683212743470724133
+I1[s683212743470724133] 683212743470724133 s683212743470724133 683212743470724133
+I2[683212743470724133, s683212743470724133] 683212743470724133 s683212743470724133 683212743470724133
+I2p[683212743470724133] 683212743470724133 s683212743470724133 683212743470724133
+PK[2049638230412172401] 2049638230412172401 s2049638230412172401 2049638230412172401
+I1[s2049638230412172401] 2049638230412172401 s2049638230412172401 2049638230412172401
+I2[2049638230412172401, s2049638230412172401] 2049638230412172401 s2049638230412172401 2049638230412172401
+I2p[2049638230412172401] 2049638230412172401 s2049638230412172401 2049638230412172401
+PK[6148914691236517205] 6148914691236517205 s6148914691236517205 6148914691236517205
+I1[s6148914691236517205] 6148914691236517205 s6148914691236517205 6148914691236517205
+I2[6148914691236517205, s6148914691236517205] 6148914691236517205 s6148914691236517205 6148914691236517205
+I2p[6148914691236517205] 6148914691236517205 s6148914691236517205 6148914691236517205
+PK[18446744073709551615] 18446744073709551615 s18446744073709551615 18446744073709551615
+I1[s18446744073709551615] 18446744073709551615 s18446744073709551615 18446744073709551615
+I2[18446744073709551615, s18446744073709551615] 18446744073709551615 s18446744073709551615 18446744073709551615
+I2p[18446744073709551615] 18446744073709551615 s18446744073709551615 18446744073709551615
+
+TYPE FLOAT
+DUMP_TABLE_BEGIN
+-32768 s-32768 -32768
+-10922 s-10922 -10922
+-3640 s-3640 -3640
+-1213 s-1213 -1213
+-404 s-404 -404
+-134 s-134 -134
+-1 s-1 -1
+0 s0 0
+1 s1 1
+134 s134 134
+404 s404 404
+1213 s1213 1213
+3640 s3640 3640
+10922 s10922 10922
+32768 s32768 32768
+DUMP_TABLE_END
+PK[-32768] -32768 s-32768 -32768
+I1[s-32768] -32768 s-32768 -32768
+I2[-32768, s-32768] -32768 s-32768 -32768
+I2p[-32768] -32768 s-32768 -32768
+PK[-10922] -10922 s-10922 -10922
+I1[s-10922] -10922 s-10922 -10922
+I2[-10922, s-10922] -10922 s-10922 -10922
+I2p[-10922] -10922 s-10922 -10922
+PK[-3640] -3640 s-3640 -3640
+I1[s-3640] -3640 s-3640 -3640
+I2[-3640, s-3640] -3640 s-3640 -3640
+I2p[-3640] -3640 s-3640 -3640
+PK[-1213] -1213 s-1213 -1213
+I1[s-1213] -1213 s-1213 -1213
+I2[-1213, s-1213] -1213 s-1213 -1213
+I2p[-1213] -1213 s-1213 -1213
+PK[-404] -404 s-404 -404
+I1[s-404] -404 s-404 -404
+I2[-404, s-404] -404 s-404 -404
+I2p[-404] -404 s-404 -404
+PK[-134] -134 s-134 -134
+I1[s-134] -134 s-134 -134
+I2[-134, s-134] -134 s-134 -134
+I2p[-134] -134 s-134 -134
+PK[-1] -1 s-1 -1
+I1[s-1] -1 s-1 -1
+I2[-1, s-1] -1 s-1 -1
+I2p[-1] -1 s-1 -1
+PK[0] 0 s0 0
+I1[s0] 0 s0 0
+I2[0, s0] 0 s0 0
+I2p[0] 0 s0 0
+PK[1] 1 s1 1
+I1[s1] 1 s1 1
+I2[1, s1] 1 s1 1
+I2p[1] 1 s1 1
+PK[134] 134 s134 134
+I1[s134] 134 s134 134
+I2[134, s134] 134 s134 134
+I2p[134] 134 s134 134
+PK[404] 404 s404 404
+I1[s404] 404 s404 404
+I2[404, s404] 404 s404 404
+I2p[404] 404 s404 404
+PK[1213] 1213 s1213 1213
+I1[s1213] 1213 s1213 1213
+I2[1213, s1213] 1213 s1213 1213
+I2p[1213] 1213 s1213 1213
+PK[3640] 3640 s3640 3640
+I1[s3640] 3640 s3640 3640
+I2[3640, s3640] 3640 s3640 3640
+I2p[3640] 3640 s3640 3640
+PK[10922] 10922 s10922 10922
+I1[s10922] 10922 s10922 10922
+I2[10922, s10922] 10922 s10922 10922
+I2p[10922] 10922 s10922 10922
+PK[32768] 32768 s32768 32768
+I1[s32768] 32768 s32768 32768
+I2[32768, s32768] 32768 s32768 32768
+I2p[32768] 32768 s32768 32768
+
+TYPE DOUBLE
+DUMP_TABLE_BEGIN
+-2147483648 s-2147483648 -2147483648
+-715827882 s-715827882 -715827882
+-238609294 s-238609294 -238609294
+-79536431 s-79536431 -79536431
+-26512143 s-26512143 -26512143
+-8837381 s-8837381 -8837381
+-1 s-1 -1
+0 s0 0
+1 s1 1
+8837381 s8837381 8837381
+26512143 s26512143 26512143
+79536431 s79536431 79536431
+238609294 s238609294 238609294
+715827882 s715827882 715827882
+2147483647 s2147483647 2147483647
+DUMP_TABLE_END
+PK[-2147483648] -2147483648 s-2147483648 -2147483648
+I1[s-2147483648] -2147483648 s-2147483648 -2147483648
+I2[-2147483648, s-2147483648] -2147483648 s-2147483648 -2147483648
+I2p[-2147483648] -2147483648 s-2147483648 -2147483648
+PK[-715827882] -715827882 s-715827882 -715827882
+I1[s-715827882] -715827882 s-715827882 -715827882
+I2[-715827882, s-715827882] -715827882 s-715827882 -715827882
+I2p[-715827882] -715827882 s-715827882 -715827882
+PK[-238609294] -238609294 s-238609294 -238609294
+I1[s-238609294] -238609294 s-238609294 -238609294
+I2[-238609294, s-238609294] -238609294 s-238609294 -238609294
+I2p[-238609294] -238609294 s-238609294 -238609294
+PK[-79536431] -79536431 s-79536431 -79536431
+I1[s-79536431] -79536431 s-79536431 -79536431
+I2[-79536431, s-79536431] -79536431 s-79536431 -79536431
+I2p[-79536431] -79536431 s-79536431 -79536431
+PK[-26512143] -26512143 s-26512143 -26512143
+I1[s-26512143] -26512143 s-26512143 -26512143
+I2[-26512143, s-26512143] -26512143 s-26512143 -26512143
+I2p[-26512143] -26512143 s-26512143 -26512143
+PK[-8837381] -8837381 s-8837381 -8837381
+I1[s-8837381] -8837381 s-8837381 -8837381
+I2[-8837381, s-8837381] -8837381 s-8837381 -8837381
+I2p[-8837381] -8837381 s-8837381 -8837381
+PK[-1] -1 s-1 -1
+I1[s-1] -1 s-1 -1
+I2[-1, s-1] -1 s-1 -1
+I2p[-1] -1 s-1 -1
+PK[0] 0 s0 0
+I1[s0] 0 s0 0
+I2[0, s0] 0 s0 0
+I2p[0] 0 s0 0
+PK[1] 1 s1 1
+I1[s1] 1 s1 1
+I2[1, s1] 1 s1 1
+I2p[1] 1 s1 1
+PK[8837381] 8837381 s8837381 8837381
+I1[s8837381] 8837381 s8837381 8837381
+I2[8837381, s8837381] 8837381 s8837381 8837381
+I2p[8837381] 8837381 s8837381 8837381
+PK[26512143] 26512143 s26512143 26512143
+I1[s26512143] 26512143 s26512143 26512143
+I2[26512143, s26512143] 26512143 s26512143 26512143
+I2p[26512143] 26512143 s26512143 26512143
+PK[79536431] 79536431 s79536431 79536431
+I1[s79536431] 79536431 s79536431 79536431
+I2[79536431, s79536431] 79536431 s79536431 79536431
+I2p[79536431] 79536431 s79536431 79536431
+PK[238609294] 238609294 s238609294 238609294
+I1[s238609294] 238609294 s238609294 238609294
+I2[238609294, s238609294] 238609294 s238609294 238609294
+I2p[238609294] 238609294 s238609294 238609294
+PK[715827882] 715827882 s715827882 715827882
+I1[s715827882] 715827882 s715827882 715827882
+I2[715827882, s715827882] 715827882 s715827882 715827882
+I2p[715827882] 715827882 s715827882 715827882
+PK[2147483647] 2147483647 s2147483647 2147483647
+I1[s2147483647] 2147483647 s2147483647 2147483647
+I2[2147483647, s2147483647] 2147483647 s2147483647 2147483647
+I2p[2147483647] 2147483647 s2147483647 2147483647
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test15.pl b/plugin/handler_socket/regtest/test_01_lib/test15.pl
new file mode 100644
index 00000000..2205be5b
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test15.pl
@@ -0,0 +1,114 @@
+#!/usr/bin/env perl
+
+# vim:sw=2:ai
+
+# test for various numeric types
+
+BEGIN {
+ push @INC, "../common/";
+};
+
+use strict;
+use warnings;
+use bigint;
+use hstest;
+
+my $numeric_types = [
+ [ 'TINYINT', -128, 127 ],
+ [ 'TINYINT UNSIGNED', 0, 255 ],
+ [ 'SMALLINT', -32768, 32768 ],
+ [ 'SMALLINT UNSIGNED', 0, 65535 ],
+ [ 'MEDIUMINT', -8388608, 8388607 ],
+ [ 'MEDIUMINT UNSIGNED', 0, 16777215 ],
+ [ 'INT', -2147483648, 2147483647 ],
+ [ 'INT UNSIGNED', 0, 4294967295 ],
+ [ 'BIGINT', -9223372036854775808, 9223372036854775807 ],
+ [ 'BIGINT UNSIGNED', 0, 18446744073709551615 ],
+ [ 'FLOAT', -32768, 32768 ],
+ [ 'DOUBLE', -2147483648, 2147483647 ],
+];
+
+my $table = 'hstesttbl';
+my $dbh;
+for my $rec (@$numeric_types) {
+ my ($typ, $minval, $maxval) = @$rec;
+ my @vals = ();
+ push(@vals, 0);
+ push(@vals, 1);
+ push(@vals, $maxval);
+ if ($minval != 0) {
+ push(@vals, -1);
+ push(@vals, $minval);
+ }
+ my $v1 = $minval;
+ my $v2 = $maxval;
+ for (my $i = 0; $i < 5; ++$i) {
+ $v1 /= 3;
+ $v2 /= 3;
+ if ($v1 != 0) {
+ push(@vals, int($v1));
+ }
+ push(@vals, int($v2));
+ }
+ @vals = sort { $a <=> $b } @vals;
+ print("TYPE $typ\n");
+ test_one($typ, \@vals);
+ print("\n");
+}
+
+sub test_one {
+ my ($typ, $values) = @_;
+ $dbh = hstest::init_testdb();
+ $dbh->do(
+ "create table $table (" .
+ "k $typ primary key, " .
+ "v1 varchar(512), " .
+ "v2 $typ, " .
+ "index i1(v1), index i2(v2, v1)) " .
+ "engine = myisam default charset = binary");
+ my $hs = hstest::get_hs_connection(undef, 9999);
+ my $dbname = $hstest::conf{dbname};
+ $hs->open_index(1, $dbname, $table, '', 'k,v1,v2');
+ $hs->open_index(2, $dbname, $table, 'i1', 'k,v1,v2');
+ $hs->open_index(3, $dbname, $table, 'i2', 'k,v1,v2');
+ for my $k (@$values) {
+ my $kstr = 's' . $k;
+ $hs->execute_single(1, '+', [ $k, $kstr, $k ], 0, 0);
+ }
+ dump_table();
+ for my $k (@$values) {
+ my $kstr = 's' . $k;
+ my ($rk, $rv1, $rv2);
+ my $r;
+ $r = $hs->execute_single(1, '=', [ $k ], 1, 0);
+ shift(@$r);
+ ($rk, $rv1, $rv2) = @$r;
+ print "PK[$k] $rk $rv1 $rv2\n";
+ $r = $hs->execute_single(2, '=', [ $kstr ], 1, 0);
+ shift(@$r);
+ ($rk, $rv1, $rv2) = @$r;
+ print "I1[$kstr] $rk $rv1 $rv2\n";
+ $r = $hs->execute_single(3, '=', [ $k, $kstr ], 1, 0);
+ shift(@$r);
+ ($rk, $rv1, $rv2) = @$r;
+ print "I2[$k, $kstr] $rk $rv1 $rv2\n";
+ $r = $hs->execute_single(3, '=', [ $k ], 1, 0);
+ shift(@$r);
+ ($rk, $rv1, $rv2) = @$r;
+ print "I2p[$k] $rk $rv1 $rv2\n";
+ }
+}
+
+sub dump_table {
+ print "DUMP_TABLE_BEGIN\n";
+ my $aref = $dbh->selectall_arrayref("select k,v1,v2 from $table order by k");
+ for my $row (@$aref) {
+ my ($k, $v1, $v2) = @$row;
+ $v1 = "[null]" if !defined($v1);
+ $v2 = "[null]" if !defined($v2);
+ print "$k $v1 $v2\n";
+ # print "MISMATCH\n" if ($valmap{$k} ne $v);
+ }
+ print "DUMP_TABLE_END\n";
+}
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test16.expected b/plugin/handler_socket/regtest/test_01_lib/test16.expected
new file mode 100644
index 00000000..b708b95c
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test16.expected
@@ -0,0 +1,66 @@
+TYPE DATE
+DUMP_TABLE_BEGIN
+0000-00-00 s0000-00-00 0000-00-00
+2011-01-01 s2011-01-01 2011-01-01
+9999-12-31 s9999-12-31 9999-12-31
+DUMP_TABLE_END
+PK[0000-00-00] 0000-00-00 s0000-00-00 0000-00-00
+I1[s0000-00-00] 0000-00-00 s0000-00-00 0000-00-00
+I2[0000-00-00, s0000-00-00] 0000-00-00 s0000-00-00 0000-00-00
+I2p[0000-00-00] 0000-00-00 s0000-00-00 0000-00-00
+PK[2011-01-01] 2011-01-01 s2011-01-01 2011-01-01
+I1[s2011-01-01] 2011-01-01 s2011-01-01 2011-01-01
+I2[2011-01-01, s2011-01-01] 2011-01-01 s2011-01-01 2011-01-01
+I2p[2011-01-01] 2011-01-01 s2011-01-01 2011-01-01
+PK[9999-12-31] 9999-12-31 s9999-12-31 9999-12-31
+I1[s9999-12-31] 9999-12-31 s9999-12-31 9999-12-31
+I2[9999-12-31, s9999-12-31] 9999-12-31 s9999-12-31 9999-12-31
+I2p[9999-12-31] 9999-12-31 s9999-12-31 9999-12-31
+
+TYPE DATETIME
+DUMP_TABLE_BEGIN
+0000-00-00 00:00:00 s0 0000-00-00 00:00:00
+2011-01-01 18:30:25 s2011-01-01 18:30:25 2011-01-01 18:30:25
+DUMP_TABLE_END
+PK[0] 0000-00-00 00:00:00 s0 0000-00-00 00:00:00
+I1[s0] 0000-00-00 00:00:00 s0 0000-00-00 00:00:00
+I2[0, s0] 0000-00-00 00:00:00 s0 0000-00-00 00:00:00
+I2p[0] 0000-00-00 00:00:00 s0 0000-00-00 00:00:00
+PK[2011-01-01 18:30:25] 2011-01-01 18:30:25 s2011-01-01 18:30:25 2011-01-01 18:30:25
+I1[s2011-01-01 18:30:25] 2011-01-01 18:30:25 s2011-01-01 18:30:25 2011-01-01 18:30:25
+I2[2011-01-01 18:30:25, s2011-01-01 18:30:25] 2011-01-01 18:30:25 s2011-01-01 18:30:25 2011-01-01 18:30:25
+I2p[2011-01-01 18:30:25] 2011-01-01 18:30:25 s2011-01-01 18:30:25 2011-01-01 18:30:25
+
+TYPE TIME
+DUMP_TABLE_BEGIN
+00:00:00 s0 00:00:00
+18:30:25 s18:30:25 18:30:25
+DUMP_TABLE_END
+PK[0] 00:00:00 s0 00:00:00
+I1[s0] 00:00:00 s0 00:00:00
+I2[0, s0] 00:00:00 s0 00:00:00
+I2p[0] 00:00:00 s0 00:00:00
+PK[18:30:25] 18:30:25 s18:30:25 18:30:25
+I1[s18:30:25] 18:30:25 s18:30:25 18:30:25
+I2[18:30:25, s18:30:25] 18:30:25 s18:30:25 18:30:25
+I2p[18:30:25] 18:30:25 s18:30:25 18:30:25
+
+TYPE YEAR(4)
+DUMP_TABLE_BEGIN
+1901 s1901 1901
+2011 s2011 2011
+2155 s2155 2155
+DUMP_TABLE_END
+PK[1901] 1901 s1901 1901
+I1[s1901] 1901 s1901 1901
+I2[1901, s1901] 1901 s1901 1901
+I2p[1901] 1901 s1901 1901
+PK[2011] 2011 s2011 2011
+I1[s2011] 2011 s2011 2011
+I2[2011, s2011] 2011 s2011 2011
+I2p[2011] 2011 s2011 2011
+PK[2155] 2155 s2155 2155
+I1[s2155] 2155 s2155 2155
+I2[2155, s2155] 2155 s2155 2155
+I2p[2155] 2155 s2155 2155
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test16.pl b/plugin/handler_socket/regtest/test_01_lib/test16.pl
new file mode 100644
index 00000000..c0c3fc55
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test16.pl
@@ -0,0 +1,88 @@
+#!/usr/bin/env perl
+
+# vim:sw=2:ai
+
+# test for date/datetime types
+
+BEGIN {
+ push @INC, "../common/";
+};
+
+use strict;
+use warnings;
+use bigint;
+use hstest;
+
+my $datetime_types = [
+ [ 'DATE', '0000-00-00', '2011-01-01', '9999-12-31' ],
+ [ 'DATETIME', 0, '2011-01-01 18:30:25' ],
+ [ 'TIME', 0, '18:30:25' ],
+ [ 'YEAR(4)', 1901, 2011, 2155 ],
+ # [ 'TIMESTAMP', 0, 999999999 ], # DOES NOT WORK YET
+];
+
+my $table = 'hstesttbl';
+my $dbh;
+for my $rec (@$datetime_types) {
+ my ($typ, @vals) = @$rec;
+ print("TYPE $typ\n");
+ test_one($typ, \@vals);
+ print("\n");
+}
+
+sub test_one {
+ my ($typ, $values) = @_;
+ $dbh = hstest::init_testdb();
+ $dbh->do(
+ "create table $table (" .
+ "k $typ primary key, " .
+ "v1 varchar(512), " .
+ "v2 $typ, " .
+ "index i1(v1), index i2(v2, v1)) " .
+ "engine = myisam default charset = binary");
+ my $hs = hstest::get_hs_connection(undef, 9999);
+ my $dbname = $hstest::conf{dbname};
+ $hs->open_index(1, $dbname, $table, '', 'k,v1,v2');
+ $hs->open_index(2, $dbname, $table, 'i1', 'k,v1,v2');
+ $hs->open_index(3, $dbname, $table, 'i2', 'k,v1,v2');
+ for my $k (@$values) {
+ my $kstr = 's' . $k;
+ $hs->execute_single(1, '+', [ $k, $kstr, $k ], 0, 0);
+ }
+ dump_table();
+ for my $k (@$values) {
+ my $kstr = 's' . $k;
+ my ($rk, $rv1, $rv2);
+ my $r;
+ $r = $hs->execute_single(1, '=', [ $k ], 1, 0);
+ shift(@$r);
+ ($rk, $rv1, $rv2) = @$r;
+ print "PK[$k] $rk $rv1 $rv2\n";
+ $r = $hs->execute_single(2, '=', [ $kstr ], 1, 0);
+ shift(@$r);
+ ($rk, $rv1, $rv2) = @$r;
+ print "I1[$kstr] $rk $rv1 $rv2\n";
+ $r = $hs->execute_single(3, '=', [ $k, $kstr ], 1, 0);
+ shift(@$r);
+ ($rk, $rv1, $rv2) = @$r;
+ print "I2[$k, $kstr] $rk $rv1 $rv2\n";
+ $r = $hs->execute_single(3, '=', [ $k ], 1, 0);
+ shift(@$r);
+ ($rk, $rv1, $rv2) = @$r;
+ print "I2p[$k] $rk $rv1 $rv2\n";
+ }
+}
+
+sub dump_table {
+ print "DUMP_TABLE_BEGIN\n";
+ my $aref = $dbh->selectall_arrayref("select k,v1,v2 from $table order by k");
+ for my $row (@$aref) {
+ my ($k, $v1, $v2) = @$row;
+ $v1 = "[null]" if !defined($v1);
+ $v2 = "[null]" if !defined($v2);
+ print "$k $v1 $v2\n";
+ # print "MISMATCH\n" if ($valmap{$k} ne $v);
+ }
+ print "DUMP_TABLE_END\n";
+}
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test17.expected b/plugin/handler_socket/regtest/test_01_lib/test17.expected
new file mode 100644
index 00000000..77176d31
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test17.expected
Binary files differ
diff --git a/plugin/handler_socket/regtest/test_01_lib/test17.pl b/plugin/handler_socket/regtest/test_01_lib/test17.pl
new file mode 100644
index 00000000..7c150dab
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test17.pl
@@ -0,0 +1,125 @@
+#!/usr/bin/env perl
+
+# vim:sw=2:ai
+
+# test for string types
+
+BEGIN {
+ push @INC, "../common/";
+};
+
+use strict;
+use warnings;
+use bigint;
+use hstest;
+
+my $string_types = [
+ [ 'CHAR(10)', undef, 1, 2, 5, 10 ],
+ [ 'VARCHAR(10)', undef, 1, 2, 5, 10 ],
+ [ 'BINARY(10)', undef, 1, 2, 5, 10 ],
+ [ 'VARBINARY(10)', undef, 1, 2, 5, 10 ],
+ [ 'CHAR(255)', undef, 1, 2, 5, 10, 100, 200, 255 ],
+ [ 'VARCHAR(255)', undef, 1, 2, 5, 10, 100, 200, 255 ],
+ [ 'VARCHAR(511)', undef, 1, 2, 5, 10, 100, 200, 511 ],
+ [ 'LONGTEXT', 500, 1, 2, 5, 10, 100, 200, 511 ],
+ [ 'LONGBLOB', 500, 1, 2, 5, 10, 100, 200, 511 ],
+# [ 'VARCHAR(4096)', 500, 1, 2, 5, 10, 100, 200, 255, 256, 4095 ],
+# [ 'VARCHAR(16383)', 500, 1, 2, 5, 10, 100, 200, 255, 256, 4095, 4096, 16383 ],
+# [ 'VARBINARY(16383)', 500, 1, 2, 5, 10, 100, 200, 255, 256, 4095, 4096, 16383 ],
+];
+
+my $table = 'hstesttbl';
+my $dbh;
+for my $rec (@$string_types) {
+ my ($typ, $keylen, @vs) = @$rec;
+ my @vals = ();
+ for my $len (@vs) {
+ my $s = '';
+ my @arr = ();
+ srand(999);
+ # print "$len 1\n";
+ for (my $i = 0; $i < $len; ++$i) {
+ my $v = int(rand(10));
+ $arr[$i] = chr(65 + $v);
+ }
+ # print "2\n";
+ push(@vals, join('', @arr));
+ }
+ print("TYPE $typ\n");
+ test_one($typ, $keylen, \@vals);
+ print("\n");
+}
+
+sub test_one {
+ my ($typ, $keylen, $values) = @_;
+ my $keylen_str = '';
+ if (defined($keylen)) {
+ $keylen_str = "($keylen)";
+ }
+ $dbh = hstest::init_testdb();
+ $dbh->do(
+ "create table $table (" .
+ "k $typ, " .
+ "v1 varchar(1000), " .
+ "v2 $typ, " .
+ "primary key(k$keylen_str), " .
+ "index i1(v1), index i2(v2$keylen_str, v1(300))) " .
+ "engine = myisam default charset = latin1");
+ my $hs = hstest::get_hs_connection(undef, 9999);
+ my $dbname = $hstest::conf{dbname};
+ $hs->open_index(1, $dbname, $table, '', 'k,v1,v2');
+ $hs->open_index(2, $dbname, $table, 'i1', 'k,v1,v2');
+ $hs->open_index(3, $dbname, $table, 'i2', 'k,v1,v2');
+ for my $k (@$values) {
+ my $kstr = 's' . $k;
+ $hs->execute_single(1, '+', [ $k, $kstr, $k ], 0, 0);
+ }
+ # dump_table();
+ for my $k (@$values) {
+ my $kstr = 's' . $k;
+ my ($rk, $rv1, $rv2);
+ my $r;
+ $r = $hs->execute_single(1, '=', [ $k ], 1, 0);
+ shift(@$r);
+ check_value("$typ:PK", @$r);
+ $r = $hs->execute_single(2, '=', [ $kstr ], 1, 0);
+ shift(@$r);
+ check_value("$typ:I1", @$r);
+ $r = $hs->execute_single(3, '=', [ $k, $kstr ], 1, 0);
+ shift(@$r);
+ check_value("$typ:I2", @$r);
+ $r = $hs->execute_single(3, '=', [ $k ], 1, 0);
+ shift(@$r);
+ check_value("$typ:I2p", @$r);
+ }
+}
+
+sub check_value {
+ my ($mess, $rk, $rv1, $rv2) = @_;
+ $rk ||= '';
+ $rv1 ||= '';
+ $rv2 ||= '';
+ if ($rv2 ne $rk) {
+ print "$mess: V2 NE\n$rk\n$rv2\n";
+ return;
+ }
+ if ($rv1 ne 's' . $rk) {
+ print "$mess: V1 NE\n$rk\n$rv1\n";
+ return;
+ }
+ print "$mess: EQ\n";
+}
+
+sub dump_table {
+ print "DUMP_TABLE_BEGIN\n";
+ my $aref = $dbh->selectall_arrayref("select k,v1,v2 from $table order by k");
+ for my $row (@$aref) {
+ my ($k, $v1, $v2) = @$row;
+ $v1 = "[null]" if !defined($v1);
+ $v2 = "[null]" if !defined($v2);
+ print "$k $v1 $v2\n";
+ # print "MISMATCH\n" if ($valmap{$k} ne $v);
+ }
+ print "DUMP_TABLE_END\n";
+}
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test18.expected b/plugin/handler_socket/regtest/test_01_lib/test18.expected
new file mode 100644
index 00000000..9e09341c
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test18.expected
@@ -0,0 +1,22 @@
+HSINSERT
+1 v1hs_0
+2 v1hs_1
+3 v1hs_2
+4 v1hs_3
+5 v1hs_4
+6 v1hs_5
+7 v1hs_6
+8 v1hs_7
+9 v1hs_8
+10 v1hs_9
+DUMP_TABLE
+1 v1hs_0
+2 v1hs_1
+3 v1hs_2
+4 v1hs_3
+5 v1hs_4
+6 v1hs_5
+7 v1hs_6
+8 v1hs_7
+9 v1hs_8
+10 v1hs_9
diff --git a/plugin/handler_socket/regtest/test_01_lib/test18.pl b/plugin/handler_socket/regtest/test_01_lib/test18.pl
new file mode 100644
index 00000000..7854642a
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test18.pl
@@ -0,0 +1,63 @@
+#!/usr/bin/env perl
+
+# vim:sw=2:ai
+
+# tests that columns to be inserted are specified by open_index
+
+BEGIN {
+ push @INC, "../common/";
+};
+
+use strict;
+use warnings;
+use hstest;
+
+my $dbh = hstest::init_testdb();
+my $table = 'hstesttbl';
+my $tablesize = 10;
+$dbh->do(
+ "create table $table (" .
+ "k int primary key auto_increment, " .
+ "v1 varchar(30), " .
+ "v2 varchar(30)) " .
+ "engine = myisam default charset = binary");
+srand(999);
+
+my %valmap = ();
+
+print "HSINSERT\n";
+my $hs = hstest::get_hs_connection(undef, 9999);
+my $dbname = $hstest::conf{dbname};
+$hs->open_index(1, $dbname, $table, '', 'v1');
+# inserts with auto_increment
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = 0;
+ my $v1 = "v1hs_" . $i;
+ my $v2 = "v2hs_" . $i;
+ my $r = $hs->execute_insert(1, [ $v1 ]);
+ my $err = $r->[0];
+ if ($err != 0) {
+ my $err_str = $r->[1];
+ print "$err $err_str\n";
+ } else {
+ my $id = $r->[1];
+ print "$id $v1\n";
+ }
+}
+
+undef $hs;
+
+dump_table();
+
+sub dump_table {
+ print "DUMP_TABLE\n";
+ my $aref = $dbh->selectall_arrayref("select k,v1,v2 from $table order by k");
+ for my $row (@$aref) {
+ my ($k, $v1, $v2) = @$row;
+ $v1 = "[null]" if !defined($v1);
+ $v2 = "[null]" if !defined($v2);
+ print "$k $v1 $v2\n";
+ # print "MISMATCH\n" if ($valmap{$k} ne $v);
+ }
+}
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test19.expected b/plugin/handler_socket/regtest/test_01_lib/test19.expected
new file mode 100644
index 00000000..1c37b403
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test19.expected
@@ -0,0 +1,14894 @@
+
+TINYINT -------------------------------------------------
+
+FILTER(TINYINT) NO FILTER
+code=0 rows=30
+[0][0][0][-128]
+[0][1][0][-42]
+[0][2][0][-14]
+[0][3][0][-4]
+[0][4][0][0]
+[0][5][0][4]
+[0][6][0][14]
+[0][7][0][42]
+[0][8][0][127]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][4][1][0]
+[1][5][1][4]
+[1][6][1][14]
+[1][7][1][42]
+[1][8][1][127]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][4][2][0]
+[2][5][2][4]
+[2][6][2][14]
+[2][7][2][42]
+[2][8][2][127]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 = -128
+code=0 rows=3
+[0][0][0][-128]
+[1][0][1][-128]
+[2][0][2][-128]
+
+FILTER(TINYINT) v2 != -128
+code=0 rows=27
+[0][1][0][-42]
+[0][2][0][-14]
+[0][3][0][-4]
+[0][4][0][0]
+[0][5][0][4]
+[0][6][0][14]
+[0][7][0][42]
+[0][8][0][127]
+[0][9][0][NULL]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][4][1][0]
+[1][5][1][4]
+[1][6][1][14]
+[1][7][1][42]
+[1][8][1][127]
+[1][9][1][NULL]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][4][2][0]
+[2][5][2][4]
+[2][6][2][14]
+[2][7][2][42]
+[2][8][2][127]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 >= -128
+code=0 rows=27
+[0][0][0][-128]
+[0][1][0][-42]
+[0][2][0][-14]
+[0][3][0][-4]
+[0][4][0][0]
+[0][5][0][4]
+[0][6][0][14]
+[0][7][0][42]
+[0][8][0][127]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][4][1][0]
+[1][5][1][4]
+[1][6][1][14]
+[1][7][1][42]
+[1][8][1][127]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][4][2][0]
+[2][5][2][4]
+[2][6][2][14]
+[2][7][2][42]
+[2][8][2][127]
+
+FILTER(TINYINT) v2 < -128
+code=0 rows=3
+[0][9][0][NULL]
+[1][9][1][NULL]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 > -128
+code=0 rows=24
+[0][1][0][-42]
+[0][2][0][-14]
+[0][3][0][-4]
+[0][4][0][0]
+[0][5][0][4]
+[0][6][0][14]
+[0][7][0][42]
+[0][8][0][127]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][4][1][0]
+[1][5][1][4]
+[1][6][1][14]
+[1][7][1][42]
+[1][8][1][127]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][4][2][0]
+[2][5][2][4]
+[2][6][2][14]
+[2][7][2][42]
+[2][8][2][127]
+
+FILTER(TINYINT) v2 <= -128
+code=0 rows=6
+[0][0][0][-128]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 = -42
+code=0 rows=3
+[0][1][0][-42]
+[1][1][1][-42]
+[2][1][2][-42]
+
+FILTER(TINYINT) v2 != -42
+code=0 rows=27
+[0][0][0][-128]
+[0][2][0][-14]
+[0][3][0][-4]
+[0][4][0][0]
+[0][5][0][4]
+[0][6][0][14]
+[0][7][0][42]
+[0][8][0][127]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][4][1][0]
+[1][5][1][4]
+[1][6][1][14]
+[1][7][1][42]
+[1][8][1][127]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][4][2][0]
+[2][5][2][4]
+[2][6][2][14]
+[2][7][2][42]
+[2][8][2][127]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 >= -42
+code=0 rows=24
+[0][1][0][-42]
+[0][2][0][-14]
+[0][3][0][-4]
+[0][4][0][0]
+[0][5][0][4]
+[0][6][0][14]
+[0][7][0][42]
+[0][8][0][127]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][4][1][0]
+[1][5][1][4]
+[1][6][1][14]
+[1][7][1][42]
+[1][8][1][127]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][4][2][0]
+[2][5][2][4]
+[2][6][2][14]
+[2][7][2][42]
+[2][8][2][127]
+
+FILTER(TINYINT) v2 < -42
+code=0 rows=6
+[0][0][0][-128]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 > -42
+code=0 rows=21
+[0][2][0][-14]
+[0][3][0][-4]
+[0][4][0][0]
+[0][5][0][4]
+[0][6][0][14]
+[0][7][0][42]
+[0][8][0][127]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][4][1][0]
+[1][5][1][4]
+[1][6][1][14]
+[1][7][1][42]
+[1][8][1][127]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][4][2][0]
+[2][5][2][4]
+[2][6][2][14]
+[2][7][2][42]
+[2][8][2][127]
+
+FILTER(TINYINT) v2 <= -42
+code=0 rows=9
+[0][0][0][-128]
+[0][1][0][-42]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 = -14
+code=0 rows=3
+[0][2][0][-14]
+[1][2][1][-14]
+[2][2][2][-14]
+
+FILTER(TINYINT) v2 != -14
+code=0 rows=27
+[0][0][0][-128]
+[0][1][0][-42]
+[0][3][0][-4]
+[0][4][0][0]
+[0][5][0][4]
+[0][6][0][14]
+[0][7][0][42]
+[0][8][0][127]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][3][1][-4]
+[1][4][1][0]
+[1][5][1][4]
+[1][6][1][14]
+[1][7][1][42]
+[1][8][1][127]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][3][2][-4]
+[2][4][2][0]
+[2][5][2][4]
+[2][6][2][14]
+[2][7][2][42]
+[2][8][2][127]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 >= -14
+code=0 rows=21
+[0][2][0][-14]
+[0][3][0][-4]
+[0][4][0][0]
+[0][5][0][4]
+[0][6][0][14]
+[0][7][0][42]
+[0][8][0][127]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][4][1][0]
+[1][5][1][4]
+[1][6][1][14]
+[1][7][1][42]
+[1][8][1][127]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][4][2][0]
+[2][5][2][4]
+[2][6][2][14]
+[2][7][2][42]
+[2][8][2][127]
+
+FILTER(TINYINT) v2 < -14
+code=0 rows=9
+[0][0][0][-128]
+[0][1][0][-42]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 > -14
+code=0 rows=18
+[0][3][0][-4]
+[0][4][0][0]
+[0][5][0][4]
+[0][6][0][14]
+[0][7][0][42]
+[0][8][0][127]
+[1][3][1][-4]
+[1][4][1][0]
+[1][5][1][4]
+[1][6][1][14]
+[1][7][1][42]
+[1][8][1][127]
+[2][3][2][-4]
+[2][4][2][0]
+[2][5][2][4]
+[2][6][2][14]
+[2][7][2][42]
+[2][8][2][127]
+
+FILTER(TINYINT) v2 <= -14
+code=0 rows=12
+[0][0][0][-128]
+[0][1][0][-42]
+[0][2][0][-14]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 = -4
+code=0 rows=3
+[0][3][0][-4]
+[1][3][1][-4]
+[2][3][2][-4]
+
+FILTER(TINYINT) v2 != -4
+code=0 rows=27
+[0][0][0][-128]
+[0][1][0][-42]
+[0][2][0][-14]
+[0][4][0][0]
+[0][5][0][4]
+[0][6][0][14]
+[0][7][0][42]
+[0][8][0][127]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][4][1][0]
+[1][5][1][4]
+[1][6][1][14]
+[1][7][1][42]
+[1][8][1][127]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][4][2][0]
+[2][5][2][4]
+[2][6][2][14]
+[2][7][2][42]
+[2][8][2][127]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 >= -4
+code=0 rows=18
+[0][3][0][-4]
+[0][4][0][0]
+[0][5][0][4]
+[0][6][0][14]
+[0][7][0][42]
+[0][8][0][127]
+[1][3][1][-4]
+[1][4][1][0]
+[1][5][1][4]
+[1][6][1][14]
+[1][7][1][42]
+[1][8][1][127]
+[2][3][2][-4]
+[2][4][2][0]
+[2][5][2][4]
+[2][6][2][14]
+[2][7][2][42]
+[2][8][2][127]
+
+FILTER(TINYINT) v2 < -4
+code=0 rows=12
+[0][0][0][-128]
+[0][1][0][-42]
+[0][2][0][-14]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 > -4
+code=0 rows=15
+[0][4][0][0]
+[0][5][0][4]
+[0][6][0][14]
+[0][7][0][42]
+[0][8][0][127]
+[1][4][1][0]
+[1][5][1][4]
+[1][6][1][14]
+[1][7][1][42]
+[1][8][1][127]
+[2][4][2][0]
+[2][5][2][4]
+[2][6][2][14]
+[2][7][2][42]
+[2][8][2][127]
+
+FILTER(TINYINT) v2 <= -4
+code=0 rows=15
+[0][0][0][-128]
+[0][1][0][-42]
+[0][2][0][-14]
+[0][3][0][-4]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 = 0
+code=0 rows=3
+[0][4][0][0]
+[1][4][1][0]
+[2][4][2][0]
+
+FILTER(TINYINT) v2 != 0
+code=0 rows=27
+[0][0][0][-128]
+[0][1][0][-42]
+[0][2][0][-14]
+[0][3][0][-4]
+[0][5][0][4]
+[0][6][0][14]
+[0][7][0][42]
+[0][8][0][127]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][5][1][4]
+[1][6][1][14]
+[1][7][1][42]
+[1][8][1][127]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][5][2][4]
+[2][6][2][14]
+[2][7][2][42]
+[2][8][2][127]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 >= 0
+code=0 rows=15
+[0][4][0][0]
+[0][5][0][4]
+[0][6][0][14]
+[0][7][0][42]
+[0][8][0][127]
+[1][4][1][0]
+[1][5][1][4]
+[1][6][1][14]
+[1][7][1][42]
+[1][8][1][127]
+[2][4][2][0]
+[2][5][2][4]
+[2][6][2][14]
+[2][7][2][42]
+[2][8][2][127]
+
+FILTER(TINYINT) v2 < 0
+code=0 rows=15
+[0][0][0][-128]
+[0][1][0][-42]
+[0][2][0][-14]
+[0][3][0][-4]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 > 0
+code=0 rows=12
+[0][5][0][4]
+[0][6][0][14]
+[0][7][0][42]
+[0][8][0][127]
+[1][5][1][4]
+[1][6][1][14]
+[1][7][1][42]
+[1][8][1][127]
+[2][5][2][4]
+[2][6][2][14]
+[2][7][2][42]
+[2][8][2][127]
+
+FILTER(TINYINT) v2 <= 0
+code=0 rows=18
+[0][0][0][-128]
+[0][1][0][-42]
+[0][2][0][-14]
+[0][3][0][-4]
+[0][4][0][0]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][4][1][0]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][4][2][0]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 = 4
+code=0 rows=3
+[0][5][0][4]
+[1][5][1][4]
+[2][5][2][4]
+
+FILTER(TINYINT) v2 != 4
+code=0 rows=27
+[0][0][0][-128]
+[0][1][0][-42]
+[0][2][0][-14]
+[0][3][0][-4]
+[0][4][0][0]
+[0][6][0][14]
+[0][7][0][42]
+[0][8][0][127]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][4][1][0]
+[1][6][1][14]
+[1][7][1][42]
+[1][8][1][127]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][4][2][0]
+[2][6][2][14]
+[2][7][2][42]
+[2][8][2][127]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 >= 4
+code=0 rows=12
+[0][5][0][4]
+[0][6][0][14]
+[0][7][0][42]
+[0][8][0][127]
+[1][5][1][4]
+[1][6][1][14]
+[1][7][1][42]
+[1][8][1][127]
+[2][5][2][4]
+[2][6][2][14]
+[2][7][2][42]
+[2][8][2][127]
+
+FILTER(TINYINT) v2 < 4
+code=0 rows=18
+[0][0][0][-128]
+[0][1][0][-42]
+[0][2][0][-14]
+[0][3][0][-4]
+[0][4][0][0]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][4][1][0]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][4][2][0]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 > 4
+code=0 rows=9
+[0][6][0][14]
+[0][7][0][42]
+[0][8][0][127]
+[1][6][1][14]
+[1][7][1][42]
+[1][8][1][127]
+[2][6][2][14]
+[2][7][2][42]
+[2][8][2][127]
+
+FILTER(TINYINT) v2 <= 4
+code=0 rows=21
+[0][0][0][-128]
+[0][1][0][-42]
+[0][2][0][-14]
+[0][3][0][-4]
+[0][4][0][0]
+[0][5][0][4]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][4][1][0]
+[1][5][1][4]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][4][2][0]
+[2][5][2][4]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 = 14
+code=0 rows=3
+[0][6][0][14]
+[1][6][1][14]
+[2][6][2][14]
+
+FILTER(TINYINT) v2 != 14
+code=0 rows=27
+[0][0][0][-128]
+[0][1][0][-42]
+[0][2][0][-14]
+[0][3][0][-4]
+[0][4][0][0]
+[0][5][0][4]
+[0][7][0][42]
+[0][8][0][127]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][4][1][0]
+[1][5][1][4]
+[1][7][1][42]
+[1][8][1][127]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][4][2][0]
+[2][5][2][4]
+[2][7][2][42]
+[2][8][2][127]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 >= 14
+code=0 rows=9
+[0][6][0][14]
+[0][7][0][42]
+[0][8][0][127]
+[1][6][1][14]
+[1][7][1][42]
+[1][8][1][127]
+[2][6][2][14]
+[2][7][2][42]
+[2][8][2][127]
+
+FILTER(TINYINT) v2 < 14
+code=0 rows=21
+[0][0][0][-128]
+[0][1][0][-42]
+[0][2][0][-14]
+[0][3][0][-4]
+[0][4][0][0]
+[0][5][0][4]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][4][1][0]
+[1][5][1][4]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][4][2][0]
+[2][5][2][4]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 > 14
+code=0 rows=6
+[0][7][0][42]
+[0][8][0][127]
+[1][7][1][42]
+[1][8][1][127]
+[2][7][2][42]
+[2][8][2][127]
+
+FILTER(TINYINT) v2 <= 14
+code=0 rows=24
+[0][0][0][-128]
+[0][1][0][-42]
+[0][2][0][-14]
+[0][3][0][-4]
+[0][4][0][0]
+[0][5][0][4]
+[0][6][0][14]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][4][1][0]
+[1][5][1][4]
+[1][6][1][14]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][4][2][0]
+[2][5][2][4]
+[2][6][2][14]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 = 42
+code=0 rows=3
+[0][7][0][42]
+[1][7][1][42]
+[2][7][2][42]
+
+FILTER(TINYINT) v2 != 42
+code=0 rows=27
+[0][0][0][-128]
+[0][1][0][-42]
+[0][2][0][-14]
+[0][3][0][-4]
+[0][4][0][0]
+[0][5][0][4]
+[0][6][0][14]
+[0][8][0][127]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][4][1][0]
+[1][5][1][4]
+[1][6][1][14]
+[1][8][1][127]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][4][2][0]
+[2][5][2][4]
+[2][6][2][14]
+[2][8][2][127]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 >= 42
+code=0 rows=6
+[0][7][0][42]
+[0][8][0][127]
+[1][7][1][42]
+[1][8][1][127]
+[2][7][2][42]
+[2][8][2][127]
+
+FILTER(TINYINT) v2 < 42
+code=0 rows=24
+[0][0][0][-128]
+[0][1][0][-42]
+[0][2][0][-14]
+[0][3][0][-4]
+[0][4][0][0]
+[0][5][0][4]
+[0][6][0][14]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][4][1][0]
+[1][5][1][4]
+[1][6][1][14]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][4][2][0]
+[2][5][2][4]
+[2][6][2][14]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 > 42
+code=0 rows=3
+[0][8][0][127]
+[1][8][1][127]
+[2][8][2][127]
+
+FILTER(TINYINT) v2 <= 42
+code=0 rows=27
+[0][0][0][-128]
+[0][1][0][-42]
+[0][2][0][-14]
+[0][3][0][-4]
+[0][4][0][0]
+[0][5][0][4]
+[0][6][0][14]
+[0][7][0][42]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][4][1][0]
+[1][5][1][4]
+[1][6][1][14]
+[1][7][1][42]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][4][2][0]
+[2][5][2][4]
+[2][6][2][14]
+[2][7][2][42]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 = 127
+code=0 rows=3
+[0][8][0][127]
+[1][8][1][127]
+[2][8][2][127]
+
+FILTER(TINYINT) v2 != 127
+code=0 rows=27
+[0][0][0][-128]
+[0][1][0][-42]
+[0][2][0][-14]
+[0][3][0][-4]
+[0][4][0][0]
+[0][5][0][4]
+[0][6][0][14]
+[0][7][0][42]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][4][1][0]
+[1][5][1][4]
+[1][6][1][14]
+[1][7][1][42]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][4][2][0]
+[2][5][2][4]
+[2][6][2][14]
+[2][7][2][42]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 >= 127
+code=0 rows=3
+[0][8][0][127]
+[1][8][1][127]
+[2][8][2][127]
+
+FILTER(TINYINT) v2 < 127
+code=0 rows=27
+[0][0][0][-128]
+[0][1][0][-42]
+[0][2][0][-14]
+[0][3][0][-4]
+[0][4][0][0]
+[0][5][0][4]
+[0][6][0][14]
+[0][7][0][42]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][4][1][0]
+[1][5][1][4]
+[1][6][1][14]
+[1][7][1][42]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][4][2][0]
+[2][5][2][4]
+[2][6][2][14]
+[2][7][2][42]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 > 127
+code=0 rows=0
+
+FILTER(TINYINT) v2 <= 127
+code=0 rows=30
+[0][0][0][-128]
+[0][1][0][-42]
+[0][2][0][-14]
+[0][3][0][-4]
+[0][4][0][0]
+[0][5][0][4]
+[0][6][0][14]
+[0][7][0][42]
+[0][8][0][127]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][4][1][0]
+[1][5][1][4]
+[1][6][1][14]
+[1][7][1][42]
+[1][8][1][127]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][4][2][0]
+[2][5][2][4]
+[2][6][2][14]
+[2][7][2][42]
+[2][8][2][127]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 = NULL
+code=0 rows=3
+[0][9][0][NULL]
+[1][9][1][NULL]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 != NULL
+code=0 rows=27
+[0][0][0][-128]
+[0][1][0][-42]
+[0][2][0][-14]
+[0][3][0][-4]
+[0][4][0][0]
+[0][5][0][4]
+[0][6][0][14]
+[0][7][0][42]
+[0][8][0][127]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][4][1][0]
+[1][5][1][4]
+[1][6][1][14]
+[1][7][1][42]
+[1][8][1][127]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][4][2][0]
+[2][5][2][4]
+[2][6][2][14]
+[2][7][2][42]
+[2][8][2][127]
+
+FILTER(TINYINT) v2 >= NULL
+code=0 rows=30
+[0][0][0][-128]
+[0][1][0][-42]
+[0][2][0][-14]
+[0][3][0][-4]
+[0][4][0][0]
+[0][5][0][4]
+[0][6][0][14]
+[0][7][0][42]
+[0][8][0][127]
+[0][9][0][NULL]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][4][1][0]
+[1][5][1][4]
+[1][6][1][14]
+[1][7][1][42]
+[1][8][1][127]
+[1][9][1][NULL]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][4][2][0]
+[2][5][2][4]
+[2][6][2][14]
+[2][7][2][42]
+[2][8][2][127]
+[2][9][2][NULL]
+
+FILTER(TINYINT) v2 < NULL
+code=0 rows=0
+
+FILTER(TINYINT) v2 > NULL
+code=0 rows=27
+[0][0][0][-128]
+[0][1][0][-42]
+[0][2][0][-14]
+[0][3][0][-4]
+[0][4][0][0]
+[0][5][0][4]
+[0][6][0][14]
+[0][7][0][42]
+[0][8][0][127]
+[1][0][1][-128]
+[1][1][1][-42]
+[1][2][1][-14]
+[1][3][1][-4]
+[1][4][1][0]
+[1][5][1][4]
+[1][6][1][14]
+[1][7][1][42]
+[1][8][1][127]
+[2][0][2][-128]
+[2][1][2][-42]
+[2][2][2][-14]
+[2][3][2][-4]
+[2][4][2][0]
+[2][5][2][4]
+[2][6][2][14]
+[2][7][2][42]
+[2][8][2][127]
+
+FILTER(TINYINT) v2 <= NULL
+code=0 rows=3
+[0][9][0][NULL]
+[1][9][1][NULL]
+[2][9][2][NULL]
+
+
+TINYINT UNSIGNED -------------------------------------------------
+
+FILTER(TINYINT UNSIGNED) NO FILTER
+code=0 rows=18
+[0][0][0][0]
+[0][1][0][9]
+[0][2][0][28]
+[0][3][0][85]
+[0][4][0][255]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][9]
+[1][2][1][28]
+[1][3][1][85]
+[1][4][1][255]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][9]
+[2][2][2][28]
+[2][3][2][85]
+[2][4][2][255]
+[2][5][2][NULL]
+
+FILTER(TINYINT UNSIGNED) v2 = 0
+code=0 rows=3
+[0][0][0][0]
+[1][0][1][0]
+[2][0][2][0]
+
+FILTER(TINYINT UNSIGNED) v2 != 0
+code=0 rows=15
+[0][1][0][9]
+[0][2][0][28]
+[0][3][0][85]
+[0][4][0][255]
+[0][5][0][NULL]
+[1][1][1][9]
+[1][2][1][28]
+[1][3][1][85]
+[1][4][1][255]
+[1][5][1][NULL]
+[2][1][2][9]
+[2][2][2][28]
+[2][3][2][85]
+[2][4][2][255]
+[2][5][2][NULL]
+
+FILTER(TINYINT UNSIGNED) v2 >= 0
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][9]
+[0][2][0][28]
+[0][3][0][85]
+[0][4][0][255]
+[1][0][1][0]
+[1][1][1][9]
+[1][2][1][28]
+[1][3][1][85]
+[1][4][1][255]
+[2][0][2][0]
+[2][1][2][9]
+[2][2][2][28]
+[2][3][2][85]
+[2][4][2][255]
+
+FILTER(TINYINT UNSIGNED) v2 < 0
+code=0 rows=3
+[0][5][0][NULL]
+[1][5][1][NULL]
+[2][5][2][NULL]
+
+FILTER(TINYINT UNSIGNED) v2 > 0
+code=0 rows=12
+[0][1][0][9]
+[0][2][0][28]
+[0][3][0][85]
+[0][4][0][255]
+[1][1][1][9]
+[1][2][1][28]
+[1][3][1][85]
+[1][4][1][255]
+[2][1][2][9]
+[2][2][2][28]
+[2][3][2][85]
+[2][4][2][255]
+
+FILTER(TINYINT UNSIGNED) v2 <= 0
+code=0 rows=6
+[0][0][0][0]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][5][2][NULL]
+
+FILTER(TINYINT UNSIGNED) v2 = 9
+code=0 rows=3
+[0][1][0][9]
+[1][1][1][9]
+[2][1][2][9]
+
+FILTER(TINYINT UNSIGNED) v2 != 9
+code=0 rows=15
+[0][0][0][0]
+[0][2][0][28]
+[0][3][0][85]
+[0][4][0][255]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][2][1][28]
+[1][3][1][85]
+[1][4][1][255]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][2][2][28]
+[2][3][2][85]
+[2][4][2][255]
+[2][5][2][NULL]
+
+FILTER(TINYINT UNSIGNED) v2 >= 9
+code=0 rows=12
+[0][1][0][9]
+[0][2][0][28]
+[0][3][0][85]
+[0][4][0][255]
+[1][1][1][9]
+[1][2][1][28]
+[1][3][1][85]
+[1][4][1][255]
+[2][1][2][9]
+[2][2][2][28]
+[2][3][2][85]
+[2][4][2][255]
+
+FILTER(TINYINT UNSIGNED) v2 < 9
+code=0 rows=6
+[0][0][0][0]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][5][2][NULL]
+
+FILTER(TINYINT UNSIGNED) v2 > 9
+code=0 rows=9
+[0][2][0][28]
+[0][3][0][85]
+[0][4][0][255]
+[1][2][1][28]
+[1][3][1][85]
+[1][4][1][255]
+[2][2][2][28]
+[2][3][2][85]
+[2][4][2][255]
+
+FILTER(TINYINT UNSIGNED) v2 <= 9
+code=0 rows=9
+[0][0][0][0]
+[0][1][0][9]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][9]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][9]
+[2][5][2][NULL]
+
+FILTER(TINYINT UNSIGNED) v2 = 28
+code=0 rows=3
+[0][2][0][28]
+[1][2][1][28]
+[2][2][2][28]
+
+FILTER(TINYINT UNSIGNED) v2 != 28
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][9]
+[0][3][0][85]
+[0][4][0][255]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][9]
+[1][3][1][85]
+[1][4][1][255]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][9]
+[2][3][2][85]
+[2][4][2][255]
+[2][5][2][NULL]
+
+FILTER(TINYINT UNSIGNED) v2 >= 28
+code=0 rows=9
+[0][2][0][28]
+[0][3][0][85]
+[0][4][0][255]
+[1][2][1][28]
+[1][3][1][85]
+[1][4][1][255]
+[2][2][2][28]
+[2][3][2][85]
+[2][4][2][255]
+
+FILTER(TINYINT UNSIGNED) v2 < 28
+code=0 rows=9
+[0][0][0][0]
+[0][1][0][9]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][9]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][9]
+[2][5][2][NULL]
+
+FILTER(TINYINT UNSIGNED) v2 > 28
+code=0 rows=6
+[0][3][0][85]
+[0][4][0][255]
+[1][3][1][85]
+[1][4][1][255]
+[2][3][2][85]
+[2][4][2][255]
+
+FILTER(TINYINT UNSIGNED) v2 <= 28
+code=0 rows=12
+[0][0][0][0]
+[0][1][0][9]
+[0][2][0][28]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][9]
+[1][2][1][28]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][9]
+[2][2][2][28]
+[2][5][2][NULL]
+
+FILTER(TINYINT UNSIGNED) v2 = 85
+code=0 rows=3
+[0][3][0][85]
+[1][3][1][85]
+[2][3][2][85]
+
+FILTER(TINYINT UNSIGNED) v2 != 85
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][9]
+[0][2][0][28]
+[0][4][0][255]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][9]
+[1][2][1][28]
+[1][4][1][255]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][9]
+[2][2][2][28]
+[2][4][2][255]
+[2][5][2][NULL]
+
+FILTER(TINYINT UNSIGNED) v2 >= 85
+code=0 rows=6
+[0][3][0][85]
+[0][4][0][255]
+[1][3][1][85]
+[1][4][1][255]
+[2][3][2][85]
+[2][4][2][255]
+
+FILTER(TINYINT UNSIGNED) v2 < 85
+code=0 rows=12
+[0][0][0][0]
+[0][1][0][9]
+[0][2][0][28]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][9]
+[1][2][1][28]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][9]
+[2][2][2][28]
+[2][5][2][NULL]
+
+FILTER(TINYINT UNSIGNED) v2 > 85
+code=0 rows=3
+[0][4][0][255]
+[1][4][1][255]
+[2][4][2][255]
+
+FILTER(TINYINT UNSIGNED) v2 <= 85
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][9]
+[0][2][0][28]
+[0][3][0][85]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][9]
+[1][2][1][28]
+[1][3][1][85]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][9]
+[2][2][2][28]
+[2][3][2][85]
+[2][5][2][NULL]
+
+FILTER(TINYINT UNSIGNED) v2 = 255
+code=0 rows=3
+[0][4][0][255]
+[1][4][1][255]
+[2][4][2][255]
+
+FILTER(TINYINT UNSIGNED) v2 != 255
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][9]
+[0][2][0][28]
+[0][3][0][85]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][9]
+[1][2][1][28]
+[1][3][1][85]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][9]
+[2][2][2][28]
+[2][3][2][85]
+[2][5][2][NULL]
+
+FILTER(TINYINT UNSIGNED) v2 >= 255
+code=0 rows=3
+[0][4][0][255]
+[1][4][1][255]
+[2][4][2][255]
+
+FILTER(TINYINT UNSIGNED) v2 < 255
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][9]
+[0][2][0][28]
+[0][3][0][85]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][9]
+[1][2][1][28]
+[1][3][1][85]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][9]
+[2][2][2][28]
+[2][3][2][85]
+[2][5][2][NULL]
+
+FILTER(TINYINT UNSIGNED) v2 > 255
+code=0 rows=0
+
+FILTER(TINYINT UNSIGNED) v2 <= 255
+code=0 rows=18
+[0][0][0][0]
+[0][1][0][9]
+[0][2][0][28]
+[0][3][0][85]
+[0][4][0][255]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][9]
+[1][2][1][28]
+[1][3][1][85]
+[1][4][1][255]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][9]
+[2][2][2][28]
+[2][3][2][85]
+[2][4][2][255]
+[2][5][2][NULL]
+
+FILTER(TINYINT UNSIGNED) v2 = NULL
+code=0 rows=3
+[0][5][0][NULL]
+[1][5][1][NULL]
+[2][5][2][NULL]
+
+FILTER(TINYINT UNSIGNED) v2 != NULL
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][9]
+[0][2][0][28]
+[0][3][0][85]
+[0][4][0][255]
+[1][0][1][0]
+[1][1][1][9]
+[1][2][1][28]
+[1][3][1][85]
+[1][4][1][255]
+[2][0][2][0]
+[2][1][2][9]
+[2][2][2][28]
+[2][3][2][85]
+[2][4][2][255]
+
+FILTER(TINYINT UNSIGNED) v2 >= NULL
+code=0 rows=18
+[0][0][0][0]
+[0][1][0][9]
+[0][2][0][28]
+[0][3][0][85]
+[0][4][0][255]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][9]
+[1][2][1][28]
+[1][3][1][85]
+[1][4][1][255]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][9]
+[2][2][2][28]
+[2][3][2][85]
+[2][4][2][255]
+[2][5][2][NULL]
+
+FILTER(TINYINT UNSIGNED) v2 < NULL
+code=0 rows=0
+
+FILTER(TINYINT UNSIGNED) v2 > NULL
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][9]
+[0][2][0][28]
+[0][3][0][85]
+[0][4][0][255]
+[1][0][1][0]
+[1][1][1][9]
+[1][2][1][28]
+[1][3][1][85]
+[1][4][1][255]
+[2][0][2][0]
+[2][1][2][9]
+[2][2][2][28]
+[2][3][2][85]
+[2][4][2][255]
+
+FILTER(TINYINT UNSIGNED) v2 <= NULL
+code=0 rows=3
+[0][5][0][NULL]
+[1][5][1][NULL]
+[2][5][2][NULL]
+
+
+SMALLINT -------------------------------------------------
+
+FILTER(SMALLINT) NO FILTER
+code=0 rows=30
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32767]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32767]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32767]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 = -32768
+code=0 rows=3
+[0][0][0][-32768]
+[1][0][1][-32768]
+[2][0][2][-32768]
+
+FILTER(SMALLINT) v2 != -32768
+code=0 rows=27
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32767]
+[0][9][0][NULL]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32767]
+[1][9][1][NULL]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32767]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 >= -32768
+code=0 rows=27
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32767]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32767]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32767]
+
+FILTER(SMALLINT) v2 < -32768
+code=0 rows=3
+[0][9][0][NULL]
+[1][9][1][NULL]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 > -32768
+code=0 rows=24
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32767]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32767]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32767]
+
+FILTER(SMALLINT) v2 <= -32768
+code=0 rows=6
+[0][0][0][-32768]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 = -10922
+code=0 rows=3
+[0][1][0][-10922]
+[1][1][1][-10922]
+[2][1][2][-10922]
+
+FILTER(SMALLINT) v2 != -10922
+code=0 rows=27
+[0][0][0][-32768]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32767]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32767]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32767]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 >= -10922
+code=0 rows=24
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32767]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32767]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32767]
+
+FILTER(SMALLINT) v2 < -10922
+code=0 rows=6
+[0][0][0][-32768]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 > -10922
+code=0 rows=21
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32767]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32767]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32767]
+
+FILTER(SMALLINT) v2 <= -10922
+code=0 rows=9
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 = -3640
+code=0 rows=3
+[0][2][0][-3640]
+[1][2][1][-3640]
+[2][2][2][-3640]
+
+FILTER(SMALLINT) v2 != -3640
+code=0 rows=27
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32767]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32767]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32767]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 >= -3640
+code=0 rows=21
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32767]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32767]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32767]
+
+FILTER(SMALLINT) v2 < -3640
+code=0 rows=9
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 > -3640
+code=0 rows=18
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32767]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32767]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32767]
+
+FILTER(SMALLINT) v2 <= -3640
+code=0 rows=12
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 = -1213
+code=0 rows=3
+[0][3][0][-1213]
+[1][3][1][-1213]
+[2][3][2][-1213]
+
+FILTER(SMALLINT) v2 != -1213
+code=0 rows=27
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32767]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32767]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32767]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 >= -1213
+code=0 rows=18
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32767]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32767]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32767]
+
+FILTER(SMALLINT) v2 < -1213
+code=0 rows=12
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 > -1213
+code=0 rows=15
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32767]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32767]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32767]
+
+FILTER(SMALLINT) v2 <= -1213
+code=0 rows=15
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 = 0
+code=0 rows=3
+[0][4][0][0]
+[1][4][1][0]
+[2][4][2][0]
+
+FILTER(SMALLINT) v2 != 0
+code=0 rows=27
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32767]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32767]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32767]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 >= 0
+code=0 rows=15
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32767]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32767]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32767]
+
+FILTER(SMALLINT) v2 < 0
+code=0 rows=15
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 > 0
+code=0 rows=12
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32767]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32767]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32767]
+
+FILTER(SMALLINT) v2 <= 0
+code=0 rows=18
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 = 1213
+code=0 rows=3
+[0][5][0][1213]
+[1][5][1][1213]
+[2][5][2][1213]
+
+FILTER(SMALLINT) v2 != 1213
+code=0 rows=27
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32767]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32767]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32767]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 >= 1213
+code=0 rows=12
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32767]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32767]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32767]
+
+FILTER(SMALLINT) v2 < 1213
+code=0 rows=18
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 > 1213
+code=0 rows=9
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32767]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32767]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32767]
+
+FILTER(SMALLINT) v2 <= 1213
+code=0 rows=21
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 = 3640
+code=0 rows=3
+[0][6][0][3640]
+[1][6][1][3640]
+[2][6][2][3640]
+
+FILTER(SMALLINT) v2 != 3640
+code=0 rows=27
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][7][0][10922]
+[0][8][0][32767]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][7][1][10922]
+[1][8][1][32767]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][7][2][10922]
+[2][8][2][32767]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 >= 3640
+code=0 rows=9
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32767]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32767]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32767]
+
+FILTER(SMALLINT) v2 < 3640
+code=0 rows=21
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 > 3640
+code=0 rows=6
+[0][7][0][10922]
+[0][8][0][32767]
+[1][7][1][10922]
+[1][8][1][32767]
+[2][7][2][10922]
+[2][8][2][32767]
+
+FILTER(SMALLINT) v2 <= 3640
+code=0 rows=24
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 = 10922
+code=0 rows=3
+[0][7][0][10922]
+[1][7][1][10922]
+[2][7][2][10922]
+
+FILTER(SMALLINT) v2 != 10922
+code=0 rows=27
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][8][0][32767]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][8][1][32767]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][8][2][32767]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 >= 10922
+code=0 rows=6
+[0][7][0][10922]
+[0][8][0][32767]
+[1][7][1][10922]
+[1][8][1][32767]
+[2][7][2][10922]
+[2][8][2][32767]
+
+FILTER(SMALLINT) v2 < 10922
+code=0 rows=24
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 > 10922
+code=0 rows=3
+[0][8][0][32767]
+[1][8][1][32767]
+[2][8][2][32767]
+
+FILTER(SMALLINT) v2 <= 10922
+code=0 rows=27
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 = 32768
+code=0 rows=3
+[0][8][0][32767]
+[1][8][1][32767]
+[2][8][2][32767]
+
+FILTER(SMALLINT) v2 != 32768
+code=0 rows=27
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 >= 32768
+code=0 rows=3
+[0][8][0][32767]
+[1][8][1][32767]
+[2][8][2][32767]
+
+FILTER(SMALLINT) v2 < 32768
+code=0 rows=27
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 > 32768
+code=0 rows=0
+
+FILTER(SMALLINT) v2 <= 32768
+code=0 rows=30
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32767]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32767]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32767]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 = NULL
+code=0 rows=3
+[0][9][0][NULL]
+[1][9][1][NULL]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 != NULL
+code=0 rows=27
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32767]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32767]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32767]
+
+FILTER(SMALLINT) v2 >= NULL
+code=0 rows=30
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32767]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32767]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32767]
+[2][9][2][NULL]
+
+FILTER(SMALLINT) v2 < NULL
+code=0 rows=0
+
+FILTER(SMALLINT) v2 > NULL
+code=0 rows=27
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32767]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32767]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32767]
+
+FILTER(SMALLINT) v2 <= NULL
+code=0 rows=3
+[0][9][0][NULL]
+[1][9][1][NULL]
+[2][9][2][NULL]
+
+
+SMALLINT UNSIGNED -------------------------------------------------
+
+FILTER(SMALLINT UNSIGNED) NO FILTER
+code=0 rows=18
+[0][0][0][0]
+[0][1][0][2427]
+[0][2][0][7281]
+[0][3][0][21845]
+[0][4][0][65535]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][2427]
+[1][2][1][7281]
+[1][3][1][21845]
+[1][4][1][65535]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][2427]
+[2][2][2][7281]
+[2][3][2][21845]
+[2][4][2][65535]
+[2][5][2][NULL]
+
+FILTER(SMALLINT UNSIGNED) v2 = 0
+code=0 rows=3
+[0][0][0][0]
+[1][0][1][0]
+[2][0][2][0]
+
+FILTER(SMALLINT UNSIGNED) v2 != 0
+code=0 rows=15
+[0][1][0][2427]
+[0][2][0][7281]
+[0][3][0][21845]
+[0][4][0][65535]
+[0][5][0][NULL]
+[1][1][1][2427]
+[1][2][1][7281]
+[1][3][1][21845]
+[1][4][1][65535]
+[1][5][1][NULL]
+[2][1][2][2427]
+[2][2][2][7281]
+[2][3][2][21845]
+[2][4][2][65535]
+[2][5][2][NULL]
+
+FILTER(SMALLINT UNSIGNED) v2 >= 0
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][2427]
+[0][2][0][7281]
+[0][3][0][21845]
+[0][4][0][65535]
+[1][0][1][0]
+[1][1][1][2427]
+[1][2][1][7281]
+[1][3][1][21845]
+[1][4][1][65535]
+[2][0][2][0]
+[2][1][2][2427]
+[2][2][2][7281]
+[2][3][2][21845]
+[2][4][2][65535]
+
+FILTER(SMALLINT UNSIGNED) v2 < 0
+code=0 rows=3
+[0][5][0][NULL]
+[1][5][1][NULL]
+[2][5][2][NULL]
+
+FILTER(SMALLINT UNSIGNED) v2 > 0
+code=0 rows=12
+[0][1][0][2427]
+[0][2][0][7281]
+[0][3][0][21845]
+[0][4][0][65535]
+[1][1][1][2427]
+[1][2][1][7281]
+[1][3][1][21845]
+[1][4][1][65535]
+[2][1][2][2427]
+[2][2][2][7281]
+[2][3][2][21845]
+[2][4][2][65535]
+
+FILTER(SMALLINT UNSIGNED) v2 <= 0
+code=0 rows=6
+[0][0][0][0]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][5][2][NULL]
+
+FILTER(SMALLINT UNSIGNED) v2 = 2427
+code=0 rows=3
+[0][1][0][2427]
+[1][1][1][2427]
+[2][1][2][2427]
+
+FILTER(SMALLINT UNSIGNED) v2 != 2427
+code=0 rows=15
+[0][0][0][0]
+[0][2][0][7281]
+[0][3][0][21845]
+[0][4][0][65535]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][2][1][7281]
+[1][3][1][21845]
+[1][4][1][65535]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][2][2][7281]
+[2][3][2][21845]
+[2][4][2][65535]
+[2][5][2][NULL]
+
+FILTER(SMALLINT UNSIGNED) v2 >= 2427
+code=0 rows=12
+[0][1][0][2427]
+[0][2][0][7281]
+[0][3][0][21845]
+[0][4][0][65535]
+[1][1][1][2427]
+[1][2][1][7281]
+[1][3][1][21845]
+[1][4][1][65535]
+[2][1][2][2427]
+[2][2][2][7281]
+[2][3][2][21845]
+[2][4][2][65535]
+
+FILTER(SMALLINT UNSIGNED) v2 < 2427
+code=0 rows=6
+[0][0][0][0]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][5][2][NULL]
+
+FILTER(SMALLINT UNSIGNED) v2 > 2427
+code=0 rows=9
+[0][2][0][7281]
+[0][3][0][21845]
+[0][4][0][65535]
+[1][2][1][7281]
+[1][3][1][21845]
+[1][4][1][65535]
+[2][2][2][7281]
+[2][3][2][21845]
+[2][4][2][65535]
+
+FILTER(SMALLINT UNSIGNED) v2 <= 2427
+code=0 rows=9
+[0][0][0][0]
+[0][1][0][2427]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][2427]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][2427]
+[2][5][2][NULL]
+
+FILTER(SMALLINT UNSIGNED) v2 = 7281
+code=0 rows=3
+[0][2][0][7281]
+[1][2][1][7281]
+[2][2][2][7281]
+
+FILTER(SMALLINT UNSIGNED) v2 != 7281
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][2427]
+[0][3][0][21845]
+[0][4][0][65535]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][2427]
+[1][3][1][21845]
+[1][4][1][65535]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][2427]
+[2][3][2][21845]
+[2][4][2][65535]
+[2][5][2][NULL]
+
+FILTER(SMALLINT UNSIGNED) v2 >= 7281
+code=0 rows=9
+[0][2][0][7281]
+[0][3][0][21845]
+[0][4][0][65535]
+[1][2][1][7281]
+[1][3][1][21845]
+[1][4][1][65535]
+[2][2][2][7281]
+[2][3][2][21845]
+[2][4][2][65535]
+
+FILTER(SMALLINT UNSIGNED) v2 < 7281
+code=0 rows=9
+[0][0][0][0]
+[0][1][0][2427]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][2427]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][2427]
+[2][5][2][NULL]
+
+FILTER(SMALLINT UNSIGNED) v2 > 7281
+code=0 rows=6
+[0][3][0][21845]
+[0][4][0][65535]
+[1][3][1][21845]
+[1][4][1][65535]
+[2][3][2][21845]
+[2][4][2][65535]
+
+FILTER(SMALLINT UNSIGNED) v2 <= 7281
+code=0 rows=12
+[0][0][0][0]
+[0][1][0][2427]
+[0][2][0][7281]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][2427]
+[1][2][1][7281]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][2427]
+[2][2][2][7281]
+[2][5][2][NULL]
+
+FILTER(SMALLINT UNSIGNED) v2 = 21845
+code=0 rows=3
+[0][3][0][21845]
+[1][3][1][21845]
+[2][3][2][21845]
+
+FILTER(SMALLINT UNSIGNED) v2 != 21845
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][2427]
+[0][2][0][7281]
+[0][4][0][65535]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][2427]
+[1][2][1][7281]
+[1][4][1][65535]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][2427]
+[2][2][2][7281]
+[2][4][2][65535]
+[2][5][2][NULL]
+
+FILTER(SMALLINT UNSIGNED) v2 >= 21845
+code=0 rows=6
+[0][3][0][21845]
+[0][4][0][65535]
+[1][3][1][21845]
+[1][4][1][65535]
+[2][3][2][21845]
+[2][4][2][65535]
+
+FILTER(SMALLINT UNSIGNED) v2 < 21845
+code=0 rows=12
+[0][0][0][0]
+[0][1][0][2427]
+[0][2][0][7281]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][2427]
+[1][2][1][7281]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][2427]
+[2][2][2][7281]
+[2][5][2][NULL]
+
+FILTER(SMALLINT UNSIGNED) v2 > 21845
+code=0 rows=3
+[0][4][0][65535]
+[1][4][1][65535]
+[2][4][2][65535]
+
+FILTER(SMALLINT UNSIGNED) v2 <= 21845
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][2427]
+[0][2][0][7281]
+[0][3][0][21845]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][2427]
+[1][2][1][7281]
+[1][3][1][21845]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][2427]
+[2][2][2][7281]
+[2][3][2][21845]
+[2][5][2][NULL]
+
+FILTER(SMALLINT UNSIGNED) v2 = 65535
+code=0 rows=3
+[0][4][0][65535]
+[1][4][1][65535]
+[2][4][2][65535]
+
+FILTER(SMALLINT UNSIGNED) v2 != 65535
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][2427]
+[0][2][0][7281]
+[0][3][0][21845]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][2427]
+[1][2][1][7281]
+[1][3][1][21845]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][2427]
+[2][2][2][7281]
+[2][3][2][21845]
+[2][5][2][NULL]
+
+FILTER(SMALLINT UNSIGNED) v2 >= 65535
+code=0 rows=3
+[0][4][0][65535]
+[1][4][1][65535]
+[2][4][2][65535]
+
+FILTER(SMALLINT UNSIGNED) v2 < 65535
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][2427]
+[0][2][0][7281]
+[0][3][0][21845]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][2427]
+[1][2][1][7281]
+[1][3][1][21845]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][2427]
+[2][2][2][7281]
+[2][3][2][21845]
+[2][5][2][NULL]
+
+FILTER(SMALLINT UNSIGNED) v2 > 65535
+code=0 rows=0
+
+FILTER(SMALLINT UNSIGNED) v2 <= 65535
+code=0 rows=18
+[0][0][0][0]
+[0][1][0][2427]
+[0][2][0][7281]
+[0][3][0][21845]
+[0][4][0][65535]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][2427]
+[1][2][1][7281]
+[1][3][1][21845]
+[1][4][1][65535]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][2427]
+[2][2][2][7281]
+[2][3][2][21845]
+[2][4][2][65535]
+[2][5][2][NULL]
+
+FILTER(SMALLINT UNSIGNED) v2 = NULL
+code=0 rows=3
+[0][5][0][NULL]
+[1][5][1][NULL]
+[2][5][2][NULL]
+
+FILTER(SMALLINT UNSIGNED) v2 != NULL
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][2427]
+[0][2][0][7281]
+[0][3][0][21845]
+[0][4][0][65535]
+[1][0][1][0]
+[1][1][1][2427]
+[1][2][1][7281]
+[1][3][1][21845]
+[1][4][1][65535]
+[2][0][2][0]
+[2][1][2][2427]
+[2][2][2][7281]
+[2][3][2][21845]
+[2][4][2][65535]
+
+FILTER(SMALLINT UNSIGNED) v2 >= NULL
+code=0 rows=18
+[0][0][0][0]
+[0][1][0][2427]
+[0][2][0][7281]
+[0][3][0][21845]
+[0][4][0][65535]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][2427]
+[1][2][1][7281]
+[1][3][1][21845]
+[1][4][1][65535]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][2427]
+[2][2][2][7281]
+[2][3][2][21845]
+[2][4][2][65535]
+[2][5][2][NULL]
+
+FILTER(SMALLINT UNSIGNED) v2 < NULL
+code=0 rows=0
+
+FILTER(SMALLINT UNSIGNED) v2 > NULL
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][2427]
+[0][2][0][7281]
+[0][3][0][21845]
+[0][4][0][65535]
+[1][0][1][0]
+[1][1][1][2427]
+[1][2][1][7281]
+[1][3][1][21845]
+[1][4][1][65535]
+[2][0][2][0]
+[2][1][2][2427]
+[2][2][2][7281]
+[2][3][2][21845]
+[2][4][2][65535]
+
+FILTER(SMALLINT UNSIGNED) v2 <= NULL
+code=0 rows=3
+[0][5][0][NULL]
+[1][5][1][NULL]
+[2][5][2][NULL]
+
+
+MEDIUMINT -------------------------------------------------
+
+FILTER(MEDIUMINT) NO FILTER
+code=0 rows=30
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][4][0][0]
+[0][5][0][310689]
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][8][0][8388607]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][8][2][8388607]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 = -8388608
+code=0 rows=3
+[0][0][0][-8388608]
+[1][0][1][-8388608]
+[2][0][2][-8388608]
+
+FILTER(MEDIUMINT) v2 != -8388608
+code=0 rows=27
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][4][0][0]
+[0][5][0][310689]
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][8][0][8388607]
+[0][9][0][NULL]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[1][9][1][NULL]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][8][2][8388607]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 >= -8388608
+code=0 rows=27
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][4][0][0]
+[0][5][0][310689]
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][8][0][8388607]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][8][2][8388607]
+
+FILTER(MEDIUMINT) v2 < -8388608
+code=0 rows=3
+[0][9][0][NULL]
+[1][9][1][NULL]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 > -8388608
+code=0 rows=24
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][4][0][0]
+[0][5][0][310689]
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][8][0][8388607]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][8][2][8388607]
+
+FILTER(MEDIUMINT) v2 <= -8388608
+code=0 rows=6
+[0][0][0][-8388608]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 = -2796202
+code=0 rows=3
+[0][1][0][-2796202]
+[1][1][1][-2796202]
+[2][1][2][-2796202]
+
+FILTER(MEDIUMINT) v2 != -2796202
+code=0 rows=27
+[0][0][0][-8388608]
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][4][0][0]
+[0][5][0][310689]
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][8][0][8388607]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][8][2][8388607]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 >= -2796202
+code=0 rows=24
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][4][0][0]
+[0][5][0][310689]
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][8][0][8388607]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][8][2][8388607]
+
+FILTER(MEDIUMINT) v2 < -2796202
+code=0 rows=6
+[0][0][0][-8388608]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 > -2796202
+code=0 rows=21
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][4][0][0]
+[0][5][0][310689]
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][8][0][8388607]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][8][2][8388607]
+
+FILTER(MEDIUMINT) v2 <= -2796202
+code=0 rows=9
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 = -932067
+code=0 rows=3
+[0][2][0][-932067]
+[1][2][1][-932067]
+[2][2][2][-932067]
+
+FILTER(MEDIUMINT) v2 != -932067
+code=0 rows=27
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][3][0][-310689]
+[0][4][0][0]
+[0][5][0][310689]
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][8][0][8388607]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][8][2][8388607]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 >= -932067
+code=0 rows=21
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][4][0][0]
+[0][5][0][310689]
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][8][0][8388607]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][8][2][8388607]
+
+FILTER(MEDIUMINT) v2 < -932067
+code=0 rows=9
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 > -932067
+code=0 rows=18
+[0][3][0][-310689]
+[0][4][0][0]
+[0][5][0][310689]
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][8][0][8388607]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][8][2][8388607]
+
+FILTER(MEDIUMINT) v2 <= -932067
+code=0 rows=12
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 = -310689
+code=0 rows=3
+[0][3][0][-310689]
+[1][3][1][-310689]
+[2][3][2][-310689]
+
+FILTER(MEDIUMINT) v2 != -310689
+code=0 rows=27
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][4][0][0]
+[0][5][0][310689]
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][8][0][8388607]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][4][1][0]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][4][2][0]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][8][2][8388607]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 >= -310689
+code=0 rows=18
+[0][3][0][-310689]
+[0][4][0][0]
+[0][5][0][310689]
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][8][0][8388607]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][8][2][8388607]
+
+FILTER(MEDIUMINT) v2 < -310689
+code=0 rows=12
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 > -310689
+code=0 rows=15
+[0][4][0][0]
+[0][5][0][310689]
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][8][0][8388607]
+[1][4][1][0]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[2][4][2][0]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][8][2][8388607]
+
+FILTER(MEDIUMINT) v2 <= -310689
+code=0 rows=15
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 = 0
+code=0 rows=3
+[0][4][0][0]
+[1][4][1][0]
+[2][4][2][0]
+
+FILTER(MEDIUMINT) v2 != 0
+code=0 rows=27
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][5][0][310689]
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][8][0][8388607]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][8][2][8388607]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 >= 0
+code=0 rows=15
+[0][4][0][0]
+[0][5][0][310689]
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][8][0][8388607]
+[1][4][1][0]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[2][4][2][0]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][8][2][8388607]
+
+FILTER(MEDIUMINT) v2 < 0
+code=0 rows=15
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 > 0
+code=0 rows=12
+[0][5][0][310689]
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][8][0][8388607]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][8][2][8388607]
+
+FILTER(MEDIUMINT) v2 <= 0
+code=0 rows=18
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][4][0][0]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 = 310689
+code=0 rows=3
+[0][5][0][310689]
+[1][5][1][310689]
+[2][5][2][310689]
+
+FILTER(MEDIUMINT) v2 != 310689
+code=0 rows=27
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][4][0][0]
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][8][0][8388607]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][8][2][8388607]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 >= 310689
+code=0 rows=12
+[0][5][0][310689]
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][8][0][8388607]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][8][2][8388607]
+
+FILTER(MEDIUMINT) v2 < 310689
+code=0 rows=18
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][4][0][0]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 > 310689
+code=0 rows=9
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][8][0][8388607]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][8][2][8388607]
+
+FILTER(MEDIUMINT) v2 <= 310689
+code=0 rows=21
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][4][0][0]
+[0][5][0][310689]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][5][1][310689]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][5][2][310689]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 = 932067
+code=0 rows=3
+[0][6][0][932067]
+[1][6][1][932067]
+[2][6][2][932067]
+
+FILTER(MEDIUMINT) v2 != 932067
+code=0 rows=27
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][4][0][0]
+[0][5][0][310689]
+[0][7][0][2796202]
+[0][8][0][8388607]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][5][1][310689]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][5][2][310689]
+[2][7][2][2796202]
+[2][8][2][8388607]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 >= 932067
+code=0 rows=9
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][8][0][8388607]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][8][2][8388607]
+
+FILTER(MEDIUMINT) v2 < 932067
+code=0 rows=21
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][4][0][0]
+[0][5][0][310689]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][5][1][310689]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][5][2][310689]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 > 932067
+code=0 rows=6
+[0][7][0][2796202]
+[0][8][0][8388607]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[2][7][2][2796202]
+[2][8][2][8388607]
+
+FILTER(MEDIUMINT) v2 <= 932067
+code=0 rows=24
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][4][0][0]
+[0][5][0][310689]
+[0][6][0][932067]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 = 2796202
+code=0 rows=3
+[0][7][0][2796202]
+[1][7][1][2796202]
+[2][7][2][2796202]
+
+FILTER(MEDIUMINT) v2 != 2796202
+code=0 rows=27
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][4][0][0]
+[0][5][0][310689]
+[0][6][0][932067]
+[0][8][0][8388607]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][8][1][8388607]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][8][2][8388607]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 >= 2796202
+code=0 rows=6
+[0][7][0][2796202]
+[0][8][0][8388607]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[2][7][2][2796202]
+[2][8][2][8388607]
+
+FILTER(MEDIUMINT) v2 < 2796202
+code=0 rows=24
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][4][0][0]
+[0][5][0][310689]
+[0][6][0][932067]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 > 2796202
+code=0 rows=3
+[0][8][0][8388607]
+[1][8][1][8388607]
+[2][8][2][8388607]
+
+FILTER(MEDIUMINT) v2 <= 2796202
+code=0 rows=27
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][4][0][0]
+[0][5][0][310689]
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 = 8388607
+code=0 rows=3
+[0][8][0][8388607]
+[1][8][1][8388607]
+[2][8][2][8388607]
+
+FILTER(MEDIUMINT) v2 != 8388607
+code=0 rows=27
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][4][0][0]
+[0][5][0][310689]
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 >= 8388607
+code=0 rows=3
+[0][8][0][8388607]
+[1][8][1][8388607]
+[2][8][2][8388607]
+
+FILTER(MEDIUMINT) v2 < 8388607
+code=0 rows=27
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][4][0][0]
+[0][5][0][310689]
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 > 8388607
+code=0 rows=0
+
+FILTER(MEDIUMINT) v2 <= 8388607
+code=0 rows=30
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][4][0][0]
+[0][5][0][310689]
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][8][0][8388607]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][8][2][8388607]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 = NULL
+code=0 rows=3
+[0][9][0][NULL]
+[1][9][1][NULL]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 != NULL
+code=0 rows=27
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][4][0][0]
+[0][5][0][310689]
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][8][0][8388607]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][8][2][8388607]
+
+FILTER(MEDIUMINT) v2 >= NULL
+code=0 rows=30
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][4][0][0]
+[0][5][0][310689]
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][8][0][8388607]
+[0][9][0][NULL]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[1][9][1][NULL]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][8][2][8388607]
+[2][9][2][NULL]
+
+FILTER(MEDIUMINT) v2 < NULL
+code=0 rows=0
+
+FILTER(MEDIUMINT) v2 > NULL
+code=0 rows=27
+[0][0][0][-8388608]
+[0][1][0][-2796202]
+[0][2][0][-932067]
+[0][3][0][-310689]
+[0][4][0][0]
+[0][5][0][310689]
+[0][6][0][932067]
+[0][7][0][2796202]
+[0][8][0][8388607]
+[1][0][1][-8388608]
+[1][1][1][-2796202]
+[1][2][1][-932067]
+[1][3][1][-310689]
+[1][4][1][0]
+[1][5][1][310689]
+[1][6][1][932067]
+[1][7][1][2796202]
+[1][8][1][8388607]
+[2][0][2][-8388608]
+[2][1][2][-2796202]
+[2][2][2][-932067]
+[2][3][2][-310689]
+[2][4][2][0]
+[2][5][2][310689]
+[2][6][2][932067]
+[2][7][2][2796202]
+[2][8][2][8388607]
+
+FILTER(MEDIUMINT) v2 <= NULL
+code=0 rows=3
+[0][9][0][NULL]
+[1][9][1][NULL]
+[2][9][2][NULL]
+
+
+MEDIUMINT UNSIGNED -------------------------------------------------
+
+FILTER(MEDIUMINT UNSIGNED) NO FILTER
+code=0 rows=18
+[0][0][0][0]
+[0][1][0][621378]
+[0][2][0][1864135]
+[0][3][0][5592405]
+[0][4][0][16777215]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][621378]
+[1][2][1][1864135]
+[1][3][1][5592405]
+[1][4][1][16777215]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][621378]
+[2][2][2][1864135]
+[2][3][2][5592405]
+[2][4][2][16777215]
+[2][5][2][NULL]
+
+FILTER(MEDIUMINT UNSIGNED) v2 = 0
+code=0 rows=3
+[0][0][0][0]
+[1][0][1][0]
+[2][0][2][0]
+
+FILTER(MEDIUMINT UNSIGNED) v2 != 0
+code=0 rows=15
+[0][1][0][621378]
+[0][2][0][1864135]
+[0][3][0][5592405]
+[0][4][0][16777215]
+[0][5][0][NULL]
+[1][1][1][621378]
+[1][2][1][1864135]
+[1][3][1][5592405]
+[1][4][1][16777215]
+[1][5][1][NULL]
+[2][1][2][621378]
+[2][2][2][1864135]
+[2][3][2][5592405]
+[2][4][2][16777215]
+[2][5][2][NULL]
+
+FILTER(MEDIUMINT UNSIGNED) v2 >= 0
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][621378]
+[0][2][0][1864135]
+[0][3][0][5592405]
+[0][4][0][16777215]
+[1][0][1][0]
+[1][1][1][621378]
+[1][2][1][1864135]
+[1][3][1][5592405]
+[1][4][1][16777215]
+[2][0][2][0]
+[2][1][2][621378]
+[2][2][2][1864135]
+[2][3][2][5592405]
+[2][4][2][16777215]
+
+FILTER(MEDIUMINT UNSIGNED) v2 < 0
+code=0 rows=3
+[0][5][0][NULL]
+[1][5][1][NULL]
+[2][5][2][NULL]
+
+FILTER(MEDIUMINT UNSIGNED) v2 > 0
+code=0 rows=12
+[0][1][0][621378]
+[0][2][0][1864135]
+[0][3][0][5592405]
+[0][4][0][16777215]
+[1][1][1][621378]
+[1][2][1][1864135]
+[1][3][1][5592405]
+[1][4][1][16777215]
+[2][1][2][621378]
+[2][2][2][1864135]
+[2][3][2][5592405]
+[2][4][2][16777215]
+
+FILTER(MEDIUMINT UNSIGNED) v2 <= 0
+code=0 rows=6
+[0][0][0][0]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][5][2][NULL]
+
+FILTER(MEDIUMINT UNSIGNED) v2 = 621378
+code=0 rows=3
+[0][1][0][621378]
+[1][1][1][621378]
+[2][1][2][621378]
+
+FILTER(MEDIUMINT UNSIGNED) v2 != 621378
+code=0 rows=15
+[0][0][0][0]
+[0][2][0][1864135]
+[0][3][0][5592405]
+[0][4][0][16777215]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][2][1][1864135]
+[1][3][1][5592405]
+[1][4][1][16777215]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][2][2][1864135]
+[2][3][2][5592405]
+[2][4][2][16777215]
+[2][5][2][NULL]
+
+FILTER(MEDIUMINT UNSIGNED) v2 >= 621378
+code=0 rows=12
+[0][1][0][621378]
+[0][2][0][1864135]
+[0][3][0][5592405]
+[0][4][0][16777215]
+[1][1][1][621378]
+[1][2][1][1864135]
+[1][3][1][5592405]
+[1][4][1][16777215]
+[2][1][2][621378]
+[2][2][2][1864135]
+[2][3][2][5592405]
+[2][4][2][16777215]
+
+FILTER(MEDIUMINT UNSIGNED) v2 < 621378
+code=0 rows=6
+[0][0][0][0]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][5][2][NULL]
+
+FILTER(MEDIUMINT UNSIGNED) v2 > 621378
+code=0 rows=9
+[0][2][0][1864135]
+[0][3][0][5592405]
+[0][4][0][16777215]
+[1][2][1][1864135]
+[1][3][1][5592405]
+[1][4][1][16777215]
+[2][2][2][1864135]
+[2][3][2][5592405]
+[2][4][2][16777215]
+
+FILTER(MEDIUMINT UNSIGNED) v2 <= 621378
+code=0 rows=9
+[0][0][0][0]
+[0][1][0][621378]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][621378]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][621378]
+[2][5][2][NULL]
+
+FILTER(MEDIUMINT UNSIGNED) v2 = 1864135
+code=0 rows=3
+[0][2][0][1864135]
+[1][2][1][1864135]
+[2][2][2][1864135]
+
+FILTER(MEDIUMINT UNSIGNED) v2 != 1864135
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][621378]
+[0][3][0][5592405]
+[0][4][0][16777215]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][621378]
+[1][3][1][5592405]
+[1][4][1][16777215]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][621378]
+[2][3][2][5592405]
+[2][4][2][16777215]
+[2][5][2][NULL]
+
+FILTER(MEDIUMINT UNSIGNED) v2 >= 1864135
+code=0 rows=9
+[0][2][0][1864135]
+[0][3][0][5592405]
+[0][4][0][16777215]
+[1][2][1][1864135]
+[1][3][1][5592405]
+[1][4][1][16777215]
+[2][2][2][1864135]
+[2][3][2][5592405]
+[2][4][2][16777215]
+
+FILTER(MEDIUMINT UNSIGNED) v2 < 1864135
+code=0 rows=9
+[0][0][0][0]
+[0][1][0][621378]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][621378]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][621378]
+[2][5][2][NULL]
+
+FILTER(MEDIUMINT UNSIGNED) v2 > 1864135
+code=0 rows=6
+[0][3][0][5592405]
+[0][4][0][16777215]
+[1][3][1][5592405]
+[1][4][1][16777215]
+[2][3][2][5592405]
+[2][4][2][16777215]
+
+FILTER(MEDIUMINT UNSIGNED) v2 <= 1864135
+code=0 rows=12
+[0][0][0][0]
+[0][1][0][621378]
+[0][2][0][1864135]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][621378]
+[1][2][1][1864135]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][621378]
+[2][2][2][1864135]
+[2][5][2][NULL]
+
+FILTER(MEDIUMINT UNSIGNED) v2 = 5592405
+code=0 rows=3
+[0][3][0][5592405]
+[1][3][1][5592405]
+[2][3][2][5592405]
+
+FILTER(MEDIUMINT UNSIGNED) v2 != 5592405
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][621378]
+[0][2][0][1864135]
+[0][4][0][16777215]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][621378]
+[1][2][1][1864135]
+[1][4][1][16777215]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][621378]
+[2][2][2][1864135]
+[2][4][2][16777215]
+[2][5][2][NULL]
+
+FILTER(MEDIUMINT UNSIGNED) v2 >= 5592405
+code=0 rows=6
+[0][3][0][5592405]
+[0][4][0][16777215]
+[1][3][1][5592405]
+[1][4][1][16777215]
+[2][3][2][5592405]
+[2][4][2][16777215]
+
+FILTER(MEDIUMINT UNSIGNED) v2 < 5592405
+code=0 rows=12
+[0][0][0][0]
+[0][1][0][621378]
+[0][2][0][1864135]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][621378]
+[1][2][1][1864135]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][621378]
+[2][2][2][1864135]
+[2][5][2][NULL]
+
+FILTER(MEDIUMINT UNSIGNED) v2 > 5592405
+code=0 rows=3
+[0][4][0][16777215]
+[1][4][1][16777215]
+[2][4][2][16777215]
+
+FILTER(MEDIUMINT UNSIGNED) v2 <= 5592405
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][621378]
+[0][2][0][1864135]
+[0][3][0][5592405]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][621378]
+[1][2][1][1864135]
+[1][3][1][5592405]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][621378]
+[2][2][2][1864135]
+[2][3][2][5592405]
+[2][5][2][NULL]
+
+FILTER(MEDIUMINT UNSIGNED) v2 = 16777215
+code=0 rows=3
+[0][4][0][16777215]
+[1][4][1][16777215]
+[2][4][2][16777215]
+
+FILTER(MEDIUMINT UNSIGNED) v2 != 16777215
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][621378]
+[0][2][0][1864135]
+[0][3][0][5592405]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][621378]
+[1][2][1][1864135]
+[1][3][1][5592405]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][621378]
+[2][2][2][1864135]
+[2][3][2][5592405]
+[2][5][2][NULL]
+
+FILTER(MEDIUMINT UNSIGNED) v2 >= 16777215
+code=0 rows=3
+[0][4][0][16777215]
+[1][4][1][16777215]
+[2][4][2][16777215]
+
+FILTER(MEDIUMINT UNSIGNED) v2 < 16777215
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][621378]
+[0][2][0][1864135]
+[0][3][0][5592405]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][621378]
+[1][2][1][1864135]
+[1][3][1][5592405]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][621378]
+[2][2][2][1864135]
+[2][3][2][5592405]
+[2][5][2][NULL]
+
+FILTER(MEDIUMINT UNSIGNED) v2 > 16777215
+code=0 rows=0
+
+FILTER(MEDIUMINT UNSIGNED) v2 <= 16777215
+code=0 rows=18
+[0][0][0][0]
+[0][1][0][621378]
+[0][2][0][1864135]
+[0][3][0][5592405]
+[0][4][0][16777215]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][621378]
+[1][2][1][1864135]
+[1][3][1][5592405]
+[1][4][1][16777215]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][621378]
+[2][2][2][1864135]
+[2][3][2][5592405]
+[2][4][2][16777215]
+[2][5][2][NULL]
+
+FILTER(MEDIUMINT UNSIGNED) v2 = NULL
+code=0 rows=3
+[0][5][0][NULL]
+[1][5][1][NULL]
+[2][5][2][NULL]
+
+FILTER(MEDIUMINT UNSIGNED) v2 != NULL
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][621378]
+[0][2][0][1864135]
+[0][3][0][5592405]
+[0][4][0][16777215]
+[1][0][1][0]
+[1][1][1][621378]
+[1][2][1][1864135]
+[1][3][1][5592405]
+[1][4][1][16777215]
+[2][0][2][0]
+[2][1][2][621378]
+[2][2][2][1864135]
+[2][3][2][5592405]
+[2][4][2][16777215]
+
+FILTER(MEDIUMINT UNSIGNED) v2 >= NULL
+code=0 rows=18
+[0][0][0][0]
+[0][1][0][621378]
+[0][2][0][1864135]
+[0][3][0][5592405]
+[0][4][0][16777215]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][621378]
+[1][2][1][1864135]
+[1][3][1][5592405]
+[1][4][1][16777215]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][621378]
+[2][2][2][1864135]
+[2][3][2][5592405]
+[2][4][2][16777215]
+[2][5][2][NULL]
+
+FILTER(MEDIUMINT UNSIGNED) v2 < NULL
+code=0 rows=0
+
+FILTER(MEDIUMINT UNSIGNED) v2 > NULL
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][621378]
+[0][2][0][1864135]
+[0][3][0][5592405]
+[0][4][0][16777215]
+[1][0][1][0]
+[1][1][1][621378]
+[1][2][1][1864135]
+[1][3][1][5592405]
+[1][4][1][16777215]
+[2][0][2][0]
+[2][1][2][621378]
+[2][2][2][1864135]
+[2][3][2][5592405]
+[2][4][2][16777215]
+
+FILTER(MEDIUMINT UNSIGNED) v2 <= NULL
+code=0 rows=3
+[0][5][0][NULL]
+[1][5][1][NULL]
+[2][5][2][NULL]
+
+
+INT -------------------------------------------------
+
+FILTER(INT) NO FILTER
+code=0 rows=30
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+[2][9][2][NULL]
+
+FILTER(INT) v2 = -2147483648
+code=0 rows=3
+[0][0][0][-2147483648]
+[1][0][1][-2147483648]
+[2][0][2][-2147483648]
+
+FILTER(INT) v2 != -2147483648
+code=0 rows=27
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[0][9][0][NULL]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[1][9][1][NULL]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+[2][9][2][NULL]
+
+FILTER(INT) v2 >= -2147483648
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(INT) v2 < -2147483648
+code=0 rows=3
+[0][9][0][NULL]
+[1][9][1][NULL]
+[2][9][2][NULL]
+
+FILTER(INT) v2 > -2147483648
+code=0 rows=24
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(INT) v2 <= -2147483648
+code=0 rows=6
+[0][0][0][-2147483648]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][9][2][NULL]
+
+FILTER(INT) v2 = -715827882
+code=0 rows=3
+[0][1][0][-715827882]
+[1][1][1][-715827882]
+[2][1][2][-715827882]
+
+FILTER(INT) v2 != -715827882
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+[2][9][2][NULL]
+
+FILTER(INT) v2 >= -715827882
+code=0 rows=24
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(INT) v2 < -715827882
+code=0 rows=6
+[0][0][0][-2147483648]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][9][2][NULL]
+
+FILTER(INT) v2 > -715827882
+code=0 rows=21
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(INT) v2 <= -715827882
+code=0 rows=9
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][9][2][NULL]
+
+FILTER(INT) v2 = -238609294
+code=0 rows=3
+[0][2][0][-238609294]
+[1][2][1][-238609294]
+[2][2][2][-238609294]
+
+FILTER(INT) v2 != -238609294
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+[2][9][2][NULL]
+
+FILTER(INT) v2 >= -238609294
+code=0 rows=21
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(INT) v2 < -238609294
+code=0 rows=9
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][9][2][NULL]
+
+FILTER(INT) v2 > -238609294
+code=0 rows=18
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(INT) v2 <= -238609294
+code=0 rows=12
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][9][2][NULL]
+
+FILTER(INT) v2 = -79536431
+code=0 rows=3
+[0][3][0][-79536431]
+[1][3][1][-79536431]
+[2][3][2][-79536431]
+
+FILTER(INT) v2 != -79536431
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+[2][9][2][NULL]
+
+FILTER(INT) v2 >= -79536431
+code=0 rows=18
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(INT) v2 < -79536431
+code=0 rows=12
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][9][2][NULL]
+
+FILTER(INT) v2 > -79536431
+code=0 rows=15
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(INT) v2 <= -79536431
+code=0 rows=15
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][9][2][NULL]
+
+FILTER(INT) v2 = 0
+code=0 rows=3
+[0][4][0][0]
+[1][4][1][0]
+[2][4][2][0]
+
+FILTER(INT) v2 != 0
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+[2][9][2][NULL]
+
+FILTER(INT) v2 >= 0
+code=0 rows=15
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(INT) v2 < 0
+code=0 rows=15
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][9][2][NULL]
+
+FILTER(INT) v2 > 0
+code=0 rows=12
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(INT) v2 <= 0
+code=0 rows=18
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][9][2][NULL]
+
+FILTER(INT) v2 = 79536431
+code=0 rows=3
+[0][5][0][79536431]
+[1][5][1][79536431]
+[2][5][2][79536431]
+
+FILTER(INT) v2 != 79536431
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+[2][9][2][NULL]
+
+FILTER(INT) v2 >= 79536431
+code=0 rows=12
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(INT) v2 < 79536431
+code=0 rows=18
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][9][2][NULL]
+
+FILTER(INT) v2 > 79536431
+code=0 rows=9
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(INT) v2 <= 79536431
+code=0 rows=21
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][9][2][NULL]
+
+FILTER(INT) v2 = 238609294
+code=0 rows=3
+[0][6][0][238609294]
+[1][6][1][238609294]
+[2][6][2][238609294]
+
+FILTER(INT) v2 != 238609294
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+[2][9][2][NULL]
+
+FILTER(INT) v2 >= 238609294
+code=0 rows=9
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(INT) v2 < 238609294
+code=0 rows=21
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][9][2][NULL]
+
+FILTER(INT) v2 > 238609294
+code=0 rows=6
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(INT) v2 <= 238609294
+code=0 rows=24
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][9][2][NULL]
+
+FILTER(INT) v2 = 715827882
+code=0 rows=3
+[0][7][0][715827882]
+[1][7][1][715827882]
+[2][7][2][715827882]
+
+FILTER(INT) v2 != 715827882
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][8][0][2147483647]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][8][1][2147483647]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][8][2][2147483647]
+[2][9][2][NULL]
+
+FILTER(INT) v2 >= 715827882
+code=0 rows=6
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(INT) v2 < 715827882
+code=0 rows=24
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][9][2][NULL]
+
+FILTER(INT) v2 > 715827882
+code=0 rows=3
+[0][8][0][2147483647]
+[1][8][1][2147483647]
+[2][8][2][2147483647]
+
+FILTER(INT) v2 <= 715827882
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][9][2][NULL]
+
+FILTER(INT) v2 = 2147483647
+code=0 rows=3
+[0][8][0][2147483647]
+[1][8][1][2147483647]
+[2][8][2][2147483647]
+
+FILTER(INT) v2 != 2147483647
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][9][2][NULL]
+
+FILTER(INT) v2 >= 2147483647
+code=0 rows=3
+[0][8][0][2147483647]
+[1][8][1][2147483647]
+[2][8][2][2147483647]
+
+FILTER(INT) v2 < 2147483647
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][9][2][NULL]
+
+FILTER(INT) v2 > 2147483647
+code=0 rows=0
+
+FILTER(INT) v2 <= 2147483647
+code=0 rows=30
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+[2][9][2][NULL]
+
+FILTER(INT) v2 = NULL
+code=0 rows=3
+[0][9][0][NULL]
+[1][9][1][NULL]
+[2][9][2][NULL]
+
+FILTER(INT) v2 != NULL
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(INT) v2 >= NULL
+code=0 rows=30
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+[2][9][2][NULL]
+
+FILTER(INT) v2 < NULL
+code=0 rows=0
+
+FILTER(INT) v2 > NULL
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(INT) v2 <= NULL
+code=0 rows=3
+[0][9][0][NULL]
+[1][9][1][NULL]
+[2][9][2][NULL]
+
+
+INT UNSIGNED -------------------------------------------------
+
+FILTER(INT UNSIGNED) NO FILTER
+code=0 rows=18
+[0][0][0][0]
+[0][1][0][159072862]
+[0][2][0][477218588]
+[0][3][0][1431655765]
+[0][4][0][4294967295]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][159072862]
+[1][2][1][477218588]
+[1][3][1][1431655765]
+[1][4][1][4294967295]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][159072862]
+[2][2][2][477218588]
+[2][3][2][1431655765]
+[2][4][2][4294967295]
+[2][5][2][NULL]
+
+FILTER(INT UNSIGNED) v2 = 0
+code=0 rows=3
+[0][0][0][0]
+[1][0][1][0]
+[2][0][2][0]
+
+FILTER(INT UNSIGNED) v2 != 0
+code=0 rows=15
+[0][1][0][159072862]
+[0][2][0][477218588]
+[0][3][0][1431655765]
+[0][4][0][4294967295]
+[0][5][0][NULL]
+[1][1][1][159072862]
+[1][2][1][477218588]
+[1][3][1][1431655765]
+[1][4][1][4294967295]
+[1][5][1][NULL]
+[2][1][2][159072862]
+[2][2][2][477218588]
+[2][3][2][1431655765]
+[2][4][2][4294967295]
+[2][5][2][NULL]
+
+FILTER(INT UNSIGNED) v2 >= 0
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][159072862]
+[0][2][0][477218588]
+[0][3][0][1431655765]
+[0][4][0][4294967295]
+[1][0][1][0]
+[1][1][1][159072862]
+[1][2][1][477218588]
+[1][3][1][1431655765]
+[1][4][1][4294967295]
+[2][0][2][0]
+[2][1][2][159072862]
+[2][2][2][477218588]
+[2][3][2][1431655765]
+[2][4][2][4294967295]
+
+FILTER(INT UNSIGNED) v2 < 0
+code=0 rows=3
+[0][5][0][NULL]
+[1][5][1][NULL]
+[2][5][2][NULL]
+
+FILTER(INT UNSIGNED) v2 > 0
+code=0 rows=12
+[0][1][0][159072862]
+[0][2][0][477218588]
+[0][3][0][1431655765]
+[0][4][0][4294967295]
+[1][1][1][159072862]
+[1][2][1][477218588]
+[1][3][1][1431655765]
+[1][4][1][4294967295]
+[2][1][2][159072862]
+[2][2][2][477218588]
+[2][3][2][1431655765]
+[2][4][2][4294967295]
+
+FILTER(INT UNSIGNED) v2 <= 0
+code=0 rows=6
+[0][0][0][0]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][5][2][NULL]
+
+FILTER(INT UNSIGNED) v2 = 159072862
+code=0 rows=3
+[0][1][0][159072862]
+[1][1][1][159072862]
+[2][1][2][159072862]
+
+FILTER(INT UNSIGNED) v2 != 159072862
+code=0 rows=15
+[0][0][0][0]
+[0][2][0][477218588]
+[0][3][0][1431655765]
+[0][4][0][4294967295]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][2][1][477218588]
+[1][3][1][1431655765]
+[1][4][1][4294967295]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][2][2][477218588]
+[2][3][2][1431655765]
+[2][4][2][4294967295]
+[2][5][2][NULL]
+
+FILTER(INT UNSIGNED) v2 >= 159072862
+code=0 rows=12
+[0][1][0][159072862]
+[0][2][0][477218588]
+[0][3][0][1431655765]
+[0][4][0][4294967295]
+[1][1][1][159072862]
+[1][2][1][477218588]
+[1][3][1][1431655765]
+[1][4][1][4294967295]
+[2][1][2][159072862]
+[2][2][2][477218588]
+[2][3][2][1431655765]
+[2][4][2][4294967295]
+
+FILTER(INT UNSIGNED) v2 < 159072862
+code=0 rows=6
+[0][0][0][0]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][5][2][NULL]
+
+FILTER(INT UNSIGNED) v2 > 159072862
+code=0 rows=9
+[0][2][0][477218588]
+[0][3][0][1431655765]
+[0][4][0][4294967295]
+[1][2][1][477218588]
+[1][3][1][1431655765]
+[1][4][1][4294967295]
+[2][2][2][477218588]
+[2][3][2][1431655765]
+[2][4][2][4294967295]
+
+FILTER(INT UNSIGNED) v2 <= 159072862
+code=0 rows=9
+[0][0][0][0]
+[0][1][0][159072862]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][159072862]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][159072862]
+[2][5][2][NULL]
+
+FILTER(INT UNSIGNED) v2 = 477218588
+code=0 rows=3
+[0][2][0][477218588]
+[1][2][1][477218588]
+[2][2][2][477218588]
+
+FILTER(INT UNSIGNED) v2 != 477218588
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][159072862]
+[0][3][0][1431655765]
+[0][4][0][4294967295]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][159072862]
+[1][3][1][1431655765]
+[1][4][1][4294967295]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][159072862]
+[2][3][2][1431655765]
+[2][4][2][4294967295]
+[2][5][2][NULL]
+
+FILTER(INT UNSIGNED) v2 >= 477218588
+code=0 rows=9
+[0][2][0][477218588]
+[0][3][0][1431655765]
+[0][4][0][4294967295]
+[1][2][1][477218588]
+[1][3][1][1431655765]
+[1][4][1][4294967295]
+[2][2][2][477218588]
+[2][3][2][1431655765]
+[2][4][2][4294967295]
+
+FILTER(INT UNSIGNED) v2 < 477218588
+code=0 rows=9
+[0][0][0][0]
+[0][1][0][159072862]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][159072862]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][159072862]
+[2][5][2][NULL]
+
+FILTER(INT UNSIGNED) v2 > 477218588
+code=0 rows=6
+[0][3][0][1431655765]
+[0][4][0][4294967295]
+[1][3][1][1431655765]
+[1][4][1][4294967295]
+[2][3][2][1431655765]
+[2][4][2][4294967295]
+
+FILTER(INT UNSIGNED) v2 <= 477218588
+code=0 rows=12
+[0][0][0][0]
+[0][1][0][159072862]
+[0][2][0][477218588]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][159072862]
+[1][2][1][477218588]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][159072862]
+[2][2][2][477218588]
+[2][5][2][NULL]
+
+FILTER(INT UNSIGNED) v2 = 1431655765
+code=0 rows=3
+[0][3][0][1431655765]
+[1][3][1][1431655765]
+[2][3][2][1431655765]
+
+FILTER(INT UNSIGNED) v2 != 1431655765
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][159072862]
+[0][2][0][477218588]
+[0][4][0][4294967295]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][159072862]
+[1][2][1][477218588]
+[1][4][1][4294967295]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][159072862]
+[2][2][2][477218588]
+[2][4][2][4294967295]
+[2][5][2][NULL]
+
+FILTER(INT UNSIGNED) v2 >= 1431655765
+code=0 rows=6
+[0][3][0][1431655765]
+[0][4][0][4294967295]
+[1][3][1][1431655765]
+[1][4][1][4294967295]
+[2][3][2][1431655765]
+[2][4][2][4294967295]
+
+FILTER(INT UNSIGNED) v2 < 1431655765
+code=0 rows=12
+[0][0][0][0]
+[0][1][0][159072862]
+[0][2][0][477218588]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][159072862]
+[1][2][1][477218588]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][159072862]
+[2][2][2][477218588]
+[2][5][2][NULL]
+
+FILTER(INT UNSIGNED) v2 > 1431655765
+code=0 rows=3
+[0][4][0][4294967295]
+[1][4][1][4294967295]
+[2][4][2][4294967295]
+
+FILTER(INT UNSIGNED) v2 <= 1431655765
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][159072862]
+[0][2][0][477218588]
+[0][3][0][1431655765]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][159072862]
+[1][2][1][477218588]
+[1][3][1][1431655765]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][159072862]
+[2][2][2][477218588]
+[2][3][2][1431655765]
+[2][5][2][NULL]
+
+FILTER(INT UNSIGNED) v2 = 4294967295
+code=0 rows=3
+[0][4][0][4294967295]
+[1][4][1][4294967295]
+[2][4][2][4294967295]
+
+FILTER(INT UNSIGNED) v2 != 4294967295
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][159072862]
+[0][2][0][477218588]
+[0][3][0][1431655765]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][159072862]
+[1][2][1][477218588]
+[1][3][1][1431655765]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][159072862]
+[2][2][2][477218588]
+[2][3][2][1431655765]
+[2][5][2][NULL]
+
+FILTER(INT UNSIGNED) v2 >= 4294967295
+code=0 rows=3
+[0][4][0][4294967295]
+[1][4][1][4294967295]
+[2][4][2][4294967295]
+
+FILTER(INT UNSIGNED) v2 < 4294967295
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][159072862]
+[0][2][0][477218588]
+[0][3][0][1431655765]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][159072862]
+[1][2][1][477218588]
+[1][3][1][1431655765]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][159072862]
+[2][2][2][477218588]
+[2][3][2][1431655765]
+[2][5][2][NULL]
+
+FILTER(INT UNSIGNED) v2 > 4294967295
+code=0 rows=0
+
+FILTER(INT UNSIGNED) v2 <= 4294967295
+code=0 rows=18
+[0][0][0][0]
+[0][1][0][159072862]
+[0][2][0][477218588]
+[0][3][0][1431655765]
+[0][4][0][4294967295]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][159072862]
+[1][2][1][477218588]
+[1][3][1][1431655765]
+[1][4][1][4294967295]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][159072862]
+[2][2][2][477218588]
+[2][3][2][1431655765]
+[2][4][2][4294967295]
+[2][5][2][NULL]
+
+FILTER(INT UNSIGNED) v2 = NULL
+code=0 rows=3
+[0][5][0][NULL]
+[1][5][1][NULL]
+[2][5][2][NULL]
+
+FILTER(INT UNSIGNED) v2 != NULL
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][159072862]
+[0][2][0][477218588]
+[0][3][0][1431655765]
+[0][4][0][4294967295]
+[1][0][1][0]
+[1][1][1][159072862]
+[1][2][1][477218588]
+[1][3][1][1431655765]
+[1][4][1][4294967295]
+[2][0][2][0]
+[2][1][2][159072862]
+[2][2][2][477218588]
+[2][3][2][1431655765]
+[2][4][2][4294967295]
+
+FILTER(INT UNSIGNED) v2 >= NULL
+code=0 rows=18
+[0][0][0][0]
+[0][1][0][159072862]
+[0][2][0][477218588]
+[0][3][0][1431655765]
+[0][4][0][4294967295]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][159072862]
+[1][2][1][477218588]
+[1][3][1][1431655765]
+[1][4][1][4294967295]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][159072862]
+[2][2][2][477218588]
+[2][3][2][1431655765]
+[2][4][2][4294967295]
+[2][5][2][NULL]
+
+FILTER(INT UNSIGNED) v2 < NULL
+code=0 rows=0
+
+FILTER(INT UNSIGNED) v2 > NULL
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][159072862]
+[0][2][0][477218588]
+[0][3][0][1431655765]
+[0][4][0][4294967295]
+[1][0][1][0]
+[1][1][1][159072862]
+[1][2][1][477218588]
+[1][3][1][1431655765]
+[1][4][1][4294967295]
+[2][0][2][0]
+[2][1][2][159072862]
+[2][2][2][477218588]
+[2][3][2][1431655765]
+[2][4][2][4294967295]
+
+FILTER(INT UNSIGNED) v2 <= NULL
+code=0 rows=3
+[0][5][0][NULL]
+[1][5][1][NULL]
+[2][5][2][NULL]
+
+
+BIGINT -------------------------------------------------
+
+FILTER(BIGINT) NO FILTER
+code=0 rows=30
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 = -9223372036854775808
+code=0 rows=3
+[0][0][0][-9223372036854775808]
+[1][0][1][-9223372036854775808]
+[2][0][2][-9223372036854775808]
+
+FILTER(BIGINT) v2 != -9223372036854775808
+code=0 rows=27
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[0][9][0][NULL]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[1][9][1][NULL]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 >= -9223372036854775808
+code=0 rows=27
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+
+FILTER(BIGINT) v2 < -9223372036854775808
+code=0 rows=3
+[0][9][0][NULL]
+[1][9][1][NULL]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 > -9223372036854775808
+code=0 rows=24
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+
+FILTER(BIGINT) v2 <= -9223372036854775808
+code=0 rows=6
+[0][0][0][-9223372036854775808]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 = -3074457345618258602
+code=0 rows=3
+[0][1][0][-3074457345618258602]
+[1][1][1][-3074457345618258602]
+[2][1][2][-3074457345618258602]
+
+FILTER(BIGINT) v2 != -3074457345618258602
+code=0 rows=27
+[0][0][0][-9223372036854775808]
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 >= -3074457345618258602
+code=0 rows=24
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+
+FILTER(BIGINT) v2 < -3074457345618258602
+code=0 rows=6
+[0][0][0][-9223372036854775808]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 > -3074457345618258602
+code=0 rows=21
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+
+FILTER(BIGINT) v2 <= -3074457345618258602
+code=0 rows=9
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 = -1024819115206086200
+code=0 rows=3
+[0][2][0][-1024819115206086200]
+[1][2][1][-1024819115206086200]
+[2][2][2][-1024819115206086200]
+
+FILTER(BIGINT) v2 != -1024819115206086200
+code=0 rows=27
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 >= -1024819115206086200
+code=0 rows=21
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+
+FILTER(BIGINT) v2 < -1024819115206086200
+code=0 rows=9
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 > -1024819115206086200
+code=0 rows=18
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+
+FILTER(BIGINT) v2 <= -1024819115206086200
+code=0 rows=12
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 = -341606371735362066
+code=0 rows=3
+[0][3][0][-341606371735362066]
+[1][3][1][-341606371735362066]
+[2][3][2][-341606371735362066]
+
+FILTER(BIGINT) v2 != -341606371735362066
+code=0 rows=27
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 >= -341606371735362066
+code=0 rows=18
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+
+FILTER(BIGINT) v2 < -341606371735362066
+code=0 rows=12
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 > -341606371735362066
+code=0 rows=15
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+
+FILTER(BIGINT) v2 <= -341606371735362066
+code=0 rows=15
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 = 0
+code=0 rows=3
+[0][4][0][0]
+[1][4][1][0]
+[2][4][2][0]
+
+FILTER(BIGINT) v2 != 0
+code=0 rows=27
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 >= 0
+code=0 rows=15
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+
+FILTER(BIGINT) v2 < 0
+code=0 rows=15
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 > 0
+code=0 rows=12
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+
+FILTER(BIGINT) v2 <= 0
+code=0 rows=18
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 = 341606371735362066
+code=0 rows=3
+[0][5][0][341606371735362066]
+[1][5][1][341606371735362066]
+[2][5][2][341606371735362066]
+
+FILTER(BIGINT) v2 != 341606371735362066
+code=0 rows=27
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 >= 341606371735362066
+code=0 rows=12
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+
+FILTER(BIGINT) v2 < 341606371735362066
+code=0 rows=18
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 > 341606371735362066
+code=0 rows=9
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+
+FILTER(BIGINT) v2 <= 341606371735362066
+code=0 rows=21
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 = 1024819115206086200
+code=0 rows=3
+[0][6][0][1024819115206086200]
+[1][6][1][1024819115206086200]
+[2][6][2][1024819115206086200]
+
+FILTER(BIGINT) v2 != 1024819115206086200
+code=0 rows=27
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 >= 1024819115206086200
+code=0 rows=9
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+
+FILTER(BIGINT) v2 < 1024819115206086200
+code=0 rows=21
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 > 1024819115206086200
+code=0 rows=6
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+
+FILTER(BIGINT) v2 <= 1024819115206086200
+code=0 rows=24
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 = 3074457345618258602
+code=0 rows=3
+[0][7][0][3074457345618258602]
+[1][7][1][3074457345618258602]
+[2][7][2][3074457345618258602]
+
+FILTER(BIGINT) v2 != 3074457345618258602
+code=0 rows=27
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][8][0][9223372036854775807]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][8][1][9223372036854775807]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][8][2][9223372036854775807]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 >= 3074457345618258602
+code=0 rows=6
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+
+FILTER(BIGINT) v2 < 3074457345618258602
+code=0 rows=24
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 > 3074457345618258602
+code=0 rows=3
+[0][8][0][9223372036854775807]
+[1][8][1][9223372036854775807]
+[2][8][2][9223372036854775807]
+
+FILTER(BIGINT) v2 <= 3074457345618258602
+code=0 rows=27
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 = 9223372036854775807
+code=0 rows=3
+[0][8][0][9223372036854775807]
+[1][8][1][9223372036854775807]
+[2][8][2][9223372036854775807]
+
+FILTER(BIGINT) v2 != 9223372036854775807
+code=0 rows=27
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 >= 9223372036854775807
+code=0 rows=3
+[0][8][0][9223372036854775807]
+[1][8][1][9223372036854775807]
+[2][8][2][9223372036854775807]
+
+FILTER(BIGINT) v2 < 9223372036854775807
+code=0 rows=27
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 > 9223372036854775807
+code=0 rows=0
+
+FILTER(BIGINT) v2 <= 9223372036854775807
+code=0 rows=30
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 = NULL
+code=0 rows=3
+[0][9][0][NULL]
+[1][9][1][NULL]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 != NULL
+code=0 rows=27
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+
+FILTER(BIGINT) v2 >= NULL
+code=0 rows=30
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[0][9][0][NULL]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[1][9][1][NULL]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+[2][9][2][NULL]
+
+FILTER(BIGINT) v2 < NULL
+code=0 rows=0
+
+FILTER(BIGINT) v2 > NULL
+code=0 rows=27
+[0][0][0][-9223372036854775808]
+[0][1][0][-3074457345618258602]
+[0][2][0][-1024819115206086200]
+[0][3][0][-341606371735362066]
+[0][4][0][0]
+[0][5][0][341606371735362066]
+[0][6][0][1024819115206086200]
+[0][7][0][3074457345618258602]
+[0][8][0][9223372036854775807]
+[1][0][1][-9223372036854775808]
+[1][1][1][-3074457345618258602]
+[1][2][1][-1024819115206086200]
+[1][3][1][-341606371735362066]
+[1][4][1][0]
+[1][5][1][341606371735362066]
+[1][6][1][1024819115206086200]
+[1][7][1][3074457345618258602]
+[1][8][1][9223372036854775807]
+[2][0][2][-9223372036854775808]
+[2][1][2][-3074457345618258602]
+[2][2][2][-1024819115206086200]
+[2][3][2][-341606371735362066]
+[2][4][2][0]
+[2][5][2][341606371735362066]
+[2][6][2][1024819115206086200]
+[2][7][2][3074457345618258602]
+[2][8][2][9223372036854775807]
+
+FILTER(BIGINT) v2 <= NULL
+code=0 rows=3
+[0][9][0][NULL]
+[1][9][1][NULL]
+[2][9][2][NULL]
+
+
+BIGINT UNSIGNED -------------------------------------------------
+
+FILTER(BIGINT UNSIGNED) NO FILTER
+code=0 rows=18
+[0][0][0][0]
+[0][1][0][683212743470724133]
+[0][2][0][2049638230412172401]
+[0][3][0][6148914691236517205]
+[0][4][0][18446744073709551615]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][683212743470724133]
+[1][2][1][2049638230412172401]
+[1][3][1][6148914691236517205]
+[1][4][1][18446744073709551615]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][683212743470724133]
+[2][2][2][2049638230412172401]
+[2][3][2][6148914691236517205]
+[2][4][2][18446744073709551615]
+[2][5][2][NULL]
+
+FILTER(BIGINT UNSIGNED) v2 = 0
+code=0 rows=3
+[0][0][0][0]
+[1][0][1][0]
+[2][0][2][0]
+
+FILTER(BIGINT UNSIGNED) v2 != 0
+code=0 rows=15
+[0][1][0][683212743470724133]
+[0][2][0][2049638230412172401]
+[0][3][0][6148914691236517205]
+[0][4][0][18446744073709551615]
+[0][5][0][NULL]
+[1][1][1][683212743470724133]
+[1][2][1][2049638230412172401]
+[1][3][1][6148914691236517205]
+[1][4][1][18446744073709551615]
+[1][5][1][NULL]
+[2][1][2][683212743470724133]
+[2][2][2][2049638230412172401]
+[2][3][2][6148914691236517205]
+[2][4][2][18446744073709551615]
+[2][5][2][NULL]
+
+FILTER(BIGINT UNSIGNED) v2 >= 0
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][683212743470724133]
+[0][2][0][2049638230412172401]
+[0][3][0][6148914691236517205]
+[0][4][0][18446744073709551615]
+[1][0][1][0]
+[1][1][1][683212743470724133]
+[1][2][1][2049638230412172401]
+[1][3][1][6148914691236517205]
+[1][4][1][18446744073709551615]
+[2][0][2][0]
+[2][1][2][683212743470724133]
+[2][2][2][2049638230412172401]
+[2][3][2][6148914691236517205]
+[2][4][2][18446744073709551615]
+
+FILTER(BIGINT UNSIGNED) v2 < 0
+code=0 rows=3
+[0][5][0][NULL]
+[1][5][1][NULL]
+[2][5][2][NULL]
+
+FILTER(BIGINT UNSIGNED) v2 > 0
+code=0 rows=12
+[0][1][0][683212743470724133]
+[0][2][0][2049638230412172401]
+[0][3][0][6148914691236517205]
+[0][4][0][18446744073709551615]
+[1][1][1][683212743470724133]
+[1][2][1][2049638230412172401]
+[1][3][1][6148914691236517205]
+[1][4][1][18446744073709551615]
+[2][1][2][683212743470724133]
+[2][2][2][2049638230412172401]
+[2][3][2][6148914691236517205]
+[2][4][2][18446744073709551615]
+
+FILTER(BIGINT UNSIGNED) v2 <= 0
+code=0 rows=6
+[0][0][0][0]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][5][2][NULL]
+
+FILTER(BIGINT UNSIGNED) v2 = 683212743470724133
+code=0 rows=3
+[0][1][0][683212743470724133]
+[1][1][1][683212743470724133]
+[2][1][2][683212743470724133]
+
+FILTER(BIGINT UNSIGNED) v2 != 683212743470724133
+code=0 rows=15
+[0][0][0][0]
+[0][2][0][2049638230412172401]
+[0][3][0][6148914691236517205]
+[0][4][0][18446744073709551615]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][2][1][2049638230412172401]
+[1][3][1][6148914691236517205]
+[1][4][1][18446744073709551615]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][2][2][2049638230412172401]
+[2][3][2][6148914691236517205]
+[2][4][2][18446744073709551615]
+[2][5][2][NULL]
+
+FILTER(BIGINT UNSIGNED) v2 >= 683212743470724133
+code=0 rows=12
+[0][1][0][683212743470724133]
+[0][2][0][2049638230412172401]
+[0][3][0][6148914691236517205]
+[0][4][0][18446744073709551615]
+[1][1][1][683212743470724133]
+[1][2][1][2049638230412172401]
+[1][3][1][6148914691236517205]
+[1][4][1][18446744073709551615]
+[2][1][2][683212743470724133]
+[2][2][2][2049638230412172401]
+[2][3][2][6148914691236517205]
+[2][4][2][18446744073709551615]
+
+FILTER(BIGINT UNSIGNED) v2 < 683212743470724133
+code=0 rows=6
+[0][0][0][0]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][5][2][NULL]
+
+FILTER(BIGINT UNSIGNED) v2 > 683212743470724133
+code=0 rows=9
+[0][2][0][2049638230412172401]
+[0][3][0][6148914691236517205]
+[0][4][0][18446744073709551615]
+[1][2][1][2049638230412172401]
+[1][3][1][6148914691236517205]
+[1][4][1][18446744073709551615]
+[2][2][2][2049638230412172401]
+[2][3][2][6148914691236517205]
+[2][4][2][18446744073709551615]
+
+FILTER(BIGINT UNSIGNED) v2 <= 683212743470724133
+code=0 rows=9
+[0][0][0][0]
+[0][1][0][683212743470724133]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][683212743470724133]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][683212743470724133]
+[2][5][2][NULL]
+
+FILTER(BIGINT UNSIGNED) v2 = 2049638230412172401
+code=0 rows=3
+[0][2][0][2049638230412172401]
+[1][2][1][2049638230412172401]
+[2][2][2][2049638230412172401]
+
+FILTER(BIGINT UNSIGNED) v2 != 2049638230412172401
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][683212743470724133]
+[0][3][0][6148914691236517205]
+[0][4][0][18446744073709551615]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][683212743470724133]
+[1][3][1][6148914691236517205]
+[1][4][1][18446744073709551615]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][683212743470724133]
+[2][3][2][6148914691236517205]
+[2][4][2][18446744073709551615]
+[2][5][2][NULL]
+
+FILTER(BIGINT UNSIGNED) v2 >= 2049638230412172401
+code=0 rows=9
+[0][2][0][2049638230412172401]
+[0][3][0][6148914691236517205]
+[0][4][0][18446744073709551615]
+[1][2][1][2049638230412172401]
+[1][3][1][6148914691236517205]
+[1][4][1][18446744073709551615]
+[2][2][2][2049638230412172401]
+[2][3][2][6148914691236517205]
+[2][4][2][18446744073709551615]
+
+FILTER(BIGINT UNSIGNED) v2 < 2049638230412172401
+code=0 rows=9
+[0][0][0][0]
+[0][1][0][683212743470724133]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][683212743470724133]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][683212743470724133]
+[2][5][2][NULL]
+
+FILTER(BIGINT UNSIGNED) v2 > 2049638230412172401
+code=0 rows=6
+[0][3][0][6148914691236517205]
+[0][4][0][18446744073709551615]
+[1][3][1][6148914691236517205]
+[1][4][1][18446744073709551615]
+[2][3][2][6148914691236517205]
+[2][4][2][18446744073709551615]
+
+FILTER(BIGINT UNSIGNED) v2 <= 2049638230412172401
+code=0 rows=12
+[0][0][0][0]
+[0][1][0][683212743470724133]
+[0][2][0][2049638230412172401]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][683212743470724133]
+[1][2][1][2049638230412172401]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][683212743470724133]
+[2][2][2][2049638230412172401]
+[2][5][2][NULL]
+
+FILTER(BIGINT UNSIGNED) v2 = 6148914691236517205
+code=0 rows=3
+[0][3][0][6148914691236517205]
+[1][3][1][6148914691236517205]
+[2][3][2][6148914691236517205]
+
+FILTER(BIGINT UNSIGNED) v2 != 6148914691236517205
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][683212743470724133]
+[0][2][0][2049638230412172401]
+[0][4][0][18446744073709551615]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][683212743470724133]
+[1][2][1][2049638230412172401]
+[1][4][1][18446744073709551615]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][683212743470724133]
+[2][2][2][2049638230412172401]
+[2][4][2][18446744073709551615]
+[2][5][2][NULL]
+
+FILTER(BIGINT UNSIGNED) v2 >= 6148914691236517205
+code=0 rows=6
+[0][3][0][6148914691236517205]
+[0][4][0][18446744073709551615]
+[1][3][1][6148914691236517205]
+[1][4][1][18446744073709551615]
+[2][3][2][6148914691236517205]
+[2][4][2][18446744073709551615]
+
+FILTER(BIGINT UNSIGNED) v2 < 6148914691236517205
+code=0 rows=12
+[0][0][0][0]
+[0][1][0][683212743470724133]
+[0][2][0][2049638230412172401]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][683212743470724133]
+[1][2][1][2049638230412172401]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][683212743470724133]
+[2][2][2][2049638230412172401]
+[2][5][2][NULL]
+
+FILTER(BIGINT UNSIGNED) v2 > 6148914691236517205
+code=0 rows=3
+[0][4][0][18446744073709551615]
+[1][4][1][18446744073709551615]
+[2][4][2][18446744073709551615]
+
+FILTER(BIGINT UNSIGNED) v2 <= 6148914691236517205
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][683212743470724133]
+[0][2][0][2049638230412172401]
+[0][3][0][6148914691236517205]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][683212743470724133]
+[1][2][1][2049638230412172401]
+[1][3][1][6148914691236517205]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][683212743470724133]
+[2][2][2][2049638230412172401]
+[2][3][2][6148914691236517205]
+[2][5][2][NULL]
+
+FILTER(BIGINT UNSIGNED) v2 = 18446744073709551615
+code=0 rows=3
+[0][4][0][18446744073709551615]
+[1][4][1][18446744073709551615]
+[2][4][2][18446744073709551615]
+
+FILTER(BIGINT UNSIGNED) v2 != 18446744073709551615
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][683212743470724133]
+[0][2][0][2049638230412172401]
+[0][3][0][6148914691236517205]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][683212743470724133]
+[1][2][1][2049638230412172401]
+[1][3][1][6148914691236517205]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][683212743470724133]
+[2][2][2][2049638230412172401]
+[2][3][2][6148914691236517205]
+[2][5][2][NULL]
+
+FILTER(BIGINT UNSIGNED) v2 >= 18446744073709551615
+code=0 rows=3
+[0][4][0][18446744073709551615]
+[1][4][1][18446744073709551615]
+[2][4][2][18446744073709551615]
+
+FILTER(BIGINT UNSIGNED) v2 < 18446744073709551615
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][683212743470724133]
+[0][2][0][2049638230412172401]
+[0][3][0][6148914691236517205]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][683212743470724133]
+[1][2][1][2049638230412172401]
+[1][3][1][6148914691236517205]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][683212743470724133]
+[2][2][2][2049638230412172401]
+[2][3][2][6148914691236517205]
+[2][5][2][NULL]
+
+FILTER(BIGINT UNSIGNED) v2 > 18446744073709551615
+code=0 rows=0
+
+FILTER(BIGINT UNSIGNED) v2 <= 18446744073709551615
+code=0 rows=18
+[0][0][0][0]
+[0][1][0][683212743470724133]
+[0][2][0][2049638230412172401]
+[0][3][0][6148914691236517205]
+[0][4][0][18446744073709551615]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][683212743470724133]
+[1][2][1][2049638230412172401]
+[1][3][1][6148914691236517205]
+[1][4][1][18446744073709551615]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][683212743470724133]
+[2][2][2][2049638230412172401]
+[2][3][2][6148914691236517205]
+[2][4][2][18446744073709551615]
+[2][5][2][NULL]
+
+FILTER(BIGINT UNSIGNED) v2 = NULL
+code=0 rows=3
+[0][5][0][NULL]
+[1][5][1][NULL]
+[2][5][2][NULL]
+
+FILTER(BIGINT UNSIGNED) v2 != NULL
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][683212743470724133]
+[0][2][0][2049638230412172401]
+[0][3][0][6148914691236517205]
+[0][4][0][18446744073709551615]
+[1][0][1][0]
+[1][1][1][683212743470724133]
+[1][2][1][2049638230412172401]
+[1][3][1][6148914691236517205]
+[1][4][1][18446744073709551615]
+[2][0][2][0]
+[2][1][2][683212743470724133]
+[2][2][2][2049638230412172401]
+[2][3][2][6148914691236517205]
+[2][4][2][18446744073709551615]
+
+FILTER(BIGINT UNSIGNED) v2 >= NULL
+code=0 rows=18
+[0][0][0][0]
+[0][1][0][683212743470724133]
+[0][2][0][2049638230412172401]
+[0][3][0][6148914691236517205]
+[0][4][0][18446744073709551615]
+[0][5][0][NULL]
+[1][0][1][0]
+[1][1][1][683212743470724133]
+[1][2][1][2049638230412172401]
+[1][3][1][6148914691236517205]
+[1][4][1][18446744073709551615]
+[1][5][1][NULL]
+[2][0][2][0]
+[2][1][2][683212743470724133]
+[2][2][2][2049638230412172401]
+[2][3][2][6148914691236517205]
+[2][4][2][18446744073709551615]
+[2][5][2][NULL]
+
+FILTER(BIGINT UNSIGNED) v2 < NULL
+code=0 rows=0
+
+FILTER(BIGINT UNSIGNED) v2 > NULL
+code=0 rows=15
+[0][0][0][0]
+[0][1][0][683212743470724133]
+[0][2][0][2049638230412172401]
+[0][3][0][6148914691236517205]
+[0][4][0][18446744073709551615]
+[1][0][1][0]
+[1][1][1][683212743470724133]
+[1][2][1][2049638230412172401]
+[1][3][1][6148914691236517205]
+[1][4][1][18446744073709551615]
+[2][0][2][0]
+[2][1][2][683212743470724133]
+[2][2][2][2049638230412172401]
+[2][3][2][6148914691236517205]
+[2][4][2][18446744073709551615]
+
+FILTER(BIGINT UNSIGNED) v2 <= NULL
+code=0 rows=3
+[0][5][0][NULL]
+[1][5][1][NULL]
+[2][5][2][NULL]
+
+
+FLOAT -------------------------------------------------
+
+FILTER(FLOAT) NO FILTER
+code=0 rows=30
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32768]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32768]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32768]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 = -32768
+code=0 rows=3
+[0][0][0][-32768]
+[1][0][1][-32768]
+[2][0][2][-32768]
+
+FILTER(FLOAT) v2 != -32768
+code=0 rows=27
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32768]
+[0][9][0][NULL]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32768]
+[1][9][1][NULL]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32768]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 >= -32768
+code=0 rows=27
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32768]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32768]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32768]
+
+FILTER(FLOAT) v2 < -32768
+code=0 rows=3
+[0][9][0][NULL]
+[1][9][1][NULL]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 > -32768
+code=0 rows=24
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32768]
+
+FILTER(FLOAT) v2 <= -32768
+code=0 rows=6
+[0][0][0][-32768]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 = -10922
+code=0 rows=3
+[0][1][0][-10922]
+[1][1][1][-10922]
+[2][1][2][-10922]
+
+FILTER(FLOAT) v2 != -10922
+code=0 rows=27
+[0][0][0][-32768]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32768]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32768]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32768]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 >= -10922
+code=0 rows=24
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32768]
+
+FILTER(FLOAT) v2 < -10922
+code=0 rows=6
+[0][0][0][-32768]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 > -10922
+code=0 rows=21
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32768]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32768]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32768]
+
+FILTER(FLOAT) v2 <= -10922
+code=0 rows=9
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 = -3640
+code=0 rows=3
+[0][2][0][-3640]
+[1][2][1][-3640]
+[2][2][2][-3640]
+
+FILTER(FLOAT) v2 != -3640
+code=0 rows=27
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32768]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32768]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32768]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 >= -3640
+code=0 rows=21
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32768]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32768]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32768]
+
+FILTER(FLOAT) v2 < -3640
+code=0 rows=9
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 > -3640
+code=0 rows=18
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32768]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32768]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32768]
+
+FILTER(FLOAT) v2 <= -3640
+code=0 rows=12
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 = -1213
+code=0 rows=3
+[0][3][0][-1213]
+[1][3][1][-1213]
+[2][3][2][-1213]
+
+FILTER(FLOAT) v2 != -1213
+code=0 rows=27
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32768]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32768]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32768]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 >= -1213
+code=0 rows=18
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32768]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32768]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32768]
+
+FILTER(FLOAT) v2 < -1213
+code=0 rows=12
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 > -1213
+code=0 rows=15
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32768]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32768]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32768]
+
+FILTER(FLOAT) v2 <= -1213
+code=0 rows=15
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 = 0
+code=0 rows=3
+[0][4][0][0]
+[1][4][1][0]
+[2][4][2][0]
+
+FILTER(FLOAT) v2 != 0
+code=0 rows=27
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32768]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32768]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32768]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 >= 0
+code=0 rows=15
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32768]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32768]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32768]
+
+FILTER(FLOAT) v2 < 0
+code=0 rows=15
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 > 0
+code=0 rows=12
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32768]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32768]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32768]
+
+FILTER(FLOAT) v2 <= 0
+code=0 rows=18
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 = 1213
+code=0 rows=3
+[0][5][0][1213]
+[1][5][1][1213]
+[2][5][2][1213]
+
+FILTER(FLOAT) v2 != 1213
+code=0 rows=27
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32768]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32768]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32768]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 >= 1213
+code=0 rows=12
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32768]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32768]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32768]
+
+FILTER(FLOAT) v2 < 1213
+code=0 rows=18
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 > 1213
+code=0 rows=9
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32768]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32768]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32768]
+
+FILTER(FLOAT) v2 <= 1213
+code=0 rows=21
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 = 3640
+code=0 rows=3
+[0][6][0][3640]
+[1][6][1][3640]
+[2][6][2][3640]
+
+FILTER(FLOAT) v2 != 3640
+code=0 rows=27
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][7][0][10922]
+[0][8][0][32768]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][7][1][10922]
+[1][8][1][32768]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][7][2][10922]
+[2][8][2][32768]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 >= 3640
+code=0 rows=9
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32768]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32768]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32768]
+
+FILTER(FLOAT) v2 < 3640
+code=0 rows=21
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 > 3640
+code=0 rows=6
+[0][7][0][10922]
+[0][8][0][32768]
+[1][7][1][10922]
+[1][8][1][32768]
+[2][7][2][10922]
+[2][8][2][32768]
+
+FILTER(FLOAT) v2 <= 3640
+code=0 rows=24
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 = 10922
+code=0 rows=3
+[0][7][0][10922]
+[1][7][1][10922]
+[2][7][2][10922]
+
+FILTER(FLOAT) v2 != 10922
+code=0 rows=27
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][8][0][32768]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][8][1][32768]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][8][2][32768]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 >= 10922
+code=0 rows=6
+[0][7][0][10922]
+[0][8][0][32768]
+[1][7][1][10922]
+[1][8][1][32768]
+[2][7][2][10922]
+[2][8][2][32768]
+
+FILTER(FLOAT) v2 < 10922
+code=0 rows=24
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 > 10922
+code=0 rows=3
+[0][8][0][32768]
+[1][8][1][32768]
+[2][8][2][32768]
+
+FILTER(FLOAT) v2 <= 10922
+code=0 rows=27
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 = 32768
+code=0 rows=3
+[0][8][0][32768]
+[1][8][1][32768]
+[2][8][2][32768]
+
+FILTER(FLOAT) v2 != 32768
+code=0 rows=27
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 >= 32768
+code=0 rows=3
+[0][8][0][32768]
+[1][8][1][32768]
+[2][8][2][32768]
+
+FILTER(FLOAT) v2 < 32768
+code=0 rows=27
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 > 32768
+code=0 rows=0
+
+FILTER(FLOAT) v2 <= 32768
+code=0 rows=30
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32768]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32768]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32768]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 = NULL
+code=0 rows=3
+[0][9][0][NULL]
+[1][9][1][NULL]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 != NULL
+code=0 rows=27
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32768]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32768]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32768]
+
+FILTER(FLOAT) v2 >= NULL
+code=0 rows=30
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32768]
+[0][9][0][NULL]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32768]
+[1][9][1][NULL]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32768]
+[2][9][2][NULL]
+
+FILTER(FLOAT) v2 < NULL
+code=0 rows=0
+
+FILTER(FLOAT) v2 > NULL
+code=0 rows=27
+[0][0][0][-32768]
+[0][1][0][-10922]
+[0][2][0][-3640]
+[0][3][0][-1213]
+[0][4][0][0]
+[0][5][0][1213]
+[0][6][0][3640]
+[0][7][0][10922]
+[0][8][0][32768]
+[1][0][1][-32768]
+[1][1][1][-10922]
+[1][2][1][-3640]
+[1][3][1][-1213]
+[1][4][1][0]
+[1][5][1][1213]
+[1][6][1][3640]
+[1][7][1][10922]
+[1][8][1][32768]
+[2][0][2][-32768]
+[2][1][2][-10922]
+[2][2][2][-3640]
+[2][3][2][-1213]
+[2][4][2][0]
+[2][5][2][1213]
+[2][6][2][3640]
+[2][7][2][10922]
+[2][8][2][32768]
+
+FILTER(FLOAT) v2 <= NULL
+code=0 rows=3
+[0][9][0][NULL]
+[1][9][1][NULL]
+[2][9][2][NULL]
+
+
+DOUBLE -------------------------------------------------
+
+FILTER(DOUBLE) NO FILTER
+code=0 rows=30
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 = -2147483648
+code=0 rows=3
+[0][0][0][-2147483648]
+[1][0][1][-2147483648]
+[2][0][2][-2147483648]
+
+FILTER(DOUBLE) v2 != -2147483648
+code=0 rows=27
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[0][9][0][NULL]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[1][9][1][NULL]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 >= -2147483648
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(DOUBLE) v2 < -2147483648
+code=0 rows=3
+[0][9][0][NULL]
+[1][9][1][NULL]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 > -2147483648
+code=0 rows=24
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(DOUBLE) v2 <= -2147483648
+code=0 rows=6
+[0][0][0][-2147483648]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 = -715827882
+code=0 rows=3
+[0][1][0][-715827882]
+[1][1][1][-715827882]
+[2][1][2][-715827882]
+
+FILTER(DOUBLE) v2 != -715827882
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 >= -715827882
+code=0 rows=24
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(DOUBLE) v2 < -715827882
+code=0 rows=6
+[0][0][0][-2147483648]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 > -715827882
+code=0 rows=21
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(DOUBLE) v2 <= -715827882
+code=0 rows=9
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 = -238609294
+code=0 rows=3
+[0][2][0][-238609294]
+[1][2][1][-238609294]
+[2][2][2][-238609294]
+
+FILTER(DOUBLE) v2 != -238609294
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 >= -238609294
+code=0 rows=21
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(DOUBLE) v2 < -238609294
+code=0 rows=9
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 > -238609294
+code=0 rows=18
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(DOUBLE) v2 <= -238609294
+code=0 rows=12
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 = -79536431
+code=0 rows=3
+[0][3][0][-79536431]
+[1][3][1][-79536431]
+[2][3][2][-79536431]
+
+FILTER(DOUBLE) v2 != -79536431
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 >= -79536431
+code=0 rows=18
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(DOUBLE) v2 < -79536431
+code=0 rows=12
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 > -79536431
+code=0 rows=15
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(DOUBLE) v2 <= -79536431
+code=0 rows=15
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 = 0
+code=0 rows=3
+[0][4][0][0]
+[1][4][1][0]
+[2][4][2][0]
+
+FILTER(DOUBLE) v2 != 0
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 >= 0
+code=0 rows=15
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(DOUBLE) v2 < 0
+code=0 rows=15
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 > 0
+code=0 rows=12
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(DOUBLE) v2 <= 0
+code=0 rows=18
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 = 79536431
+code=0 rows=3
+[0][5][0][79536431]
+[1][5][1][79536431]
+[2][5][2][79536431]
+
+FILTER(DOUBLE) v2 != 79536431
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 >= 79536431
+code=0 rows=12
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(DOUBLE) v2 < 79536431
+code=0 rows=18
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 > 79536431
+code=0 rows=9
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(DOUBLE) v2 <= 79536431
+code=0 rows=21
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 = 238609294
+code=0 rows=3
+[0][6][0][238609294]
+[1][6][1][238609294]
+[2][6][2][238609294]
+
+FILTER(DOUBLE) v2 != 238609294
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 >= 238609294
+code=0 rows=9
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(DOUBLE) v2 < 238609294
+code=0 rows=21
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 > 238609294
+code=0 rows=6
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(DOUBLE) v2 <= 238609294
+code=0 rows=24
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 = 715827882
+code=0 rows=3
+[0][7][0][715827882]
+[1][7][1][715827882]
+[2][7][2][715827882]
+
+FILTER(DOUBLE) v2 != 715827882
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][8][0][2147483647]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][8][1][2147483647]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][8][2][2147483647]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 >= 715827882
+code=0 rows=6
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(DOUBLE) v2 < 715827882
+code=0 rows=24
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 > 715827882
+code=0 rows=3
+[0][8][0][2147483647]
+[1][8][1][2147483647]
+[2][8][2][2147483647]
+
+FILTER(DOUBLE) v2 <= 715827882
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 = 2147483647
+code=0 rows=3
+[0][8][0][2147483647]
+[1][8][1][2147483647]
+[2][8][2][2147483647]
+
+FILTER(DOUBLE) v2 != 2147483647
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 >= 2147483647
+code=0 rows=3
+[0][8][0][2147483647]
+[1][8][1][2147483647]
+[2][8][2][2147483647]
+
+FILTER(DOUBLE) v2 < 2147483647
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 > 2147483647
+code=0 rows=0
+
+FILTER(DOUBLE) v2 <= 2147483647
+code=0 rows=30
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 = NULL
+code=0 rows=3
+[0][9][0][NULL]
+[1][9][1][NULL]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 != NULL
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(DOUBLE) v2 >= NULL
+code=0 rows=30
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[0][9][0][NULL]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[1][9][1][NULL]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+[2][9][2][NULL]
+
+FILTER(DOUBLE) v2 < NULL
+code=0 rows=0
+
+FILTER(DOUBLE) v2 > NULL
+code=0 rows=27
+[0][0][0][-2147483648]
+[0][1][0][-715827882]
+[0][2][0][-238609294]
+[0][3][0][-79536431]
+[0][4][0][0]
+[0][5][0][79536431]
+[0][6][0][238609294]
+[0][7][0][715827882]
+[0][8][0][2147483647]
+[1][0][1][-2147483648]
+[1][1][1][-715827882]
+[1][2][1][-238609294]
+[1][3][1][-79536431]
+[1][4][1][0]
+[1][5][1][79536431]
+[1][6][1][238609294]
+[1][7][1][715827882]
+[1][8][1][2147483647]
+[2][0][2][-2147483648]
+[2][1][2][-715827882]
+[2][2][2][-238609294]
+[2][3][2][-79536431]
+[2][4][2][0]
+[2][5][2][79536431]
+[2][6][2][238609294]
+[2][7][2][715827882]
+[2][8][2][2147483647]
+
+FILTER(DOUBLE) v2 <= NULL
+code=0 rows=3
+[0][9][0][NULL]
+[1][9][1][NULL]
+[2][9][2][NULL]
+
+
+DATE -------------------------------------------------
+
+FILTER(DATE) NO FILTER
+code=0 rows=12
+[0][0][0][0000-00-00]
+[0][1][0][2011-01-01]
+[0][2][0][9999-12-31]
+[0][3][0][NULL]
+[1][0][1][0000-00-00]
+[1][1][1][2011-01-01]
+[1][2][1][9999-12-31]
+[1][3][1][NULL]
+[2][0][2][0000-00-00]
+[2][1][2][2011-01-01]
+[2][2][2][9999-12-31]
+[2][3][2][NULL]
+
+FILTER(DATE) v2 = 0000-00-00
+code=0 rows=3
+[0][0][0][0000-00-00]
+[1][0][1][0000-00-00]
+[2][0][2][0000-00-00]
+
+FILTER(DATE) v2 != 0000-00-00
+code=0 rows=9
+[0][1][0][2011-01-01]
+[0][2][0][9999-12-31]
+[0][3][0][NULL]
+[1][1][1][2011-01-01]
+[1][2][1][9999-12-31]
+[1][3][1][NULL]
+[2][1][2][2011-01-01]
+[2][2][2][9999-12-31]
+[2][3][2][NULL]
+
+FILTER(DATE) v2 >= 0000-00-00
+code=0 rows=9
+[0][0][0][0000-00-00]
+[0][1][0][2011-01-01]
+[0][2][0][9999-12-31]
+[1][0][1][0000-00-00]
+[1][1][1][2011-01-01]
+[1][2][1][9999-12-31]
+[2][0][2][0000-00-00]
+[2][1][2][2011-01-01]
+[2][2][2][9999-12-31]
+
+FILTER(DATE) v2 < 0000-00-00
+code=0 rows=3
+[0][3][0][NULL]
+[1][3][1][NULL]
+[2][3][2][NULL]
+
+FILTER(DATE) v2 > 0000-00-00
+code=0 rows=6
+[0][1][0][2011-01-01]
+[0][2][0][9999-12-31]
+[1][1][1][2011-01-01]
+[1][2][1][9999-12-31]
+[2][1][2][2011-01-01]
+[2][2][2][9999-12-31]
+
+FILTER(DATE) v2 <= 0000-00-00
+code=0 rows=6
+[0][0][0][0000-00-00]
+[0][3][0][NULL]
+[1][0][1][0000-00-00]
+[1][3][1][NULL]
+[2][0][2][0000-00-00]
+[2][3][2][NULL]
+
+FILTER(DATE) v2 = 2011-01-01
+code=0 rows=3
+[0][1][0][2011-01-01]
+[1][1][1][2011-01-01]
+[2][1][2][2011-01-01]
+
+FILTER(DATE) v2 != 2011-01-01
+code=0 rows=9
+[0][0][0][0000-00-00]
+[0][2][0][9999-12-31]
+[0][3][0][NULL]
+[1][0][1][0000-00-00]
+[1][2][1][9999-12-31]
+[1][3][1][NULL]
+[2][0][2][0000-00-00]
+[2][2][2][9999-12-31]
+[2][3][2][NULL]
+
+FILTER(DATE) v2 >= 2011-01-01
+code=0 rows=6
+[0][1][0][2011-01-01]
+[0][2][0][9999-12-31]
+[1][1][1][2011-01-01]
+[1][2][1][9999-12-31]
+[2][1][2][2011-01-01]
+[2][2][2][9999-12-31]
+
+FILTER(DATE) v2 < 2011-01-01
+code=0 rows=6
+[0][0][0][0000-00-00]
+[0][3][0][NULL]
+[1][0][1][0000-00-00]
+[1][3][1][NULL]
+[2][0][2][0000-00-00]
+[2][3][2][NULL]
+
+FILTER(DATE) v2 > 2011-01-01
+code=0 rows=3
+[0][2][0][9999-12-31]
+[1][2][1][9999-12-31]
+[2][2][2][9999-12-31]
+
+FILTER(DATE) v2 <= 2011-01-01
+code=0 rows=9
+[0][0][0][0000-00-00]
+[0][1][0][2011-01-01]
+[0][3][0][NULL]
+[1][0][1][0000-00-00]
+[1][1][1][2011-01-01]
+[1][3][1][NULL]
+[2][0][2][0000-00-00]
+[2][1][2][2011-01-01]
+[2][3][2][NULL]
+
+FILTER(DATE) v2 = 9999-12-31
+code=0 rows=3
+[0][2][0][9999-12-31]
+[1][2][1][9999-12-31]
+[2][2][2][9999-12-31]
+
+FILTER(DATE) v2 != 9999-12-31
+code=0 rows=9
+[0][0][0][0000-00-00]
+[0][1][0][2011-01-01]
+[0][3][0][NULL]
+[1][0][1][0000-00-00]
+[1][1][1][2011-01-01]
+[1][3][1][NULL]
+[2][0][2][0000-00-00]
+[2][1][2][2011-01-01]
+[2][3][2][NULL]
+
+FILTER(DATE) v2 >= 9999-12-31
+code=0 rows=3
+[0][2][0][9999-12-31]
+[1][2][1][9999-12-31]
+[2][2][2][9999-12-31]
+
+FILTER(DATE) v2 < 9999-12-31
+code=0 rows=9
+[0][0][0][0000-00-00]
+[0][1][0][2011-01-01]
+[0][3][0][NULL]
+[1][0][1][0000-00-00]
+[1][1][1][2011-01-01]
+[1][3][1][NULL]
+[2][0][2][0000-00-00]
+[2][1][2][2011-01-01]
+[2][3][2][NULL]
+
+FILTER(DATE) v2 > 9999-12-31
+code=0 rows=0
+
+FILTER(DATE) v2 <= 9999-12-31
+code=0 rows=12
+[0][0][0][0000-00-00]
+[0][1][0][2011-01-01]
+[0][2][0][9999-12-31]
+[0][3][0][NULL]
+[1][0][1][0000-00-00]
+[1][1][1][2011-01-01]
+[1][2][1][9999-12-31]
+[1][3][1][NULL]
+[2][0][2][0000-00-00]
+[2][1][2][2011-01-01]
+[2][2][2][9999-12-31]
+[2][3][2][NULL]
+
+FILTER(DATE) v2 = NULL
+code=0 rows=3
+[0][3][0][NULL]
+[1][3][1][NULL]
+[2][3][2][NULL]
+
+FILTER(DATE) v2 != NULL
+code=0 rows=9
+[0][0][0][0000-00-00]
+[0][1][0][2011-01-01]
+[0][2][0][9999-12-31]
+[1][0][1][0000-00-00]
+[1][1][1][2011-01-01]
+[1][2][1][9999-12-31]
+[2][0][2][0000-00-00]
+[2][1][2][2011-01-01]
+[2][2][2][9999-12-31]
+
+FILTER(DATE) v2 >= NULL
+code=0 rows=12
+[0][0][0][0000-00-00]
+[0][1][0][2011-01-01]
+[0][2][0][9999-12-31]
+[0][3][0][NULL]
+[1][0][1][0000-00-00]
+[1][1][1][2011-01-01]
+[1][2][1][9999-12-31]
+[1][3][1][NULL]
+[2][0][2][0000-00-00]
+[2][1][2][2011-01-01]
+[2][2][2][9999-12-31]
+[2][3][2][NULL]
+
+FILTER(DATE) v2 < NULL
+code=0 rows=0
+
+FILTER(DATE) v2 > NULL
+code=0 rows=9
+[0][0][0][0000-00-00]
+[0][1][0][2011-01-01]
+[0][2][0][9999-12-31]
+[1][0][1][0000-00-00]
+[1][1][1][2011-01-01]
+[1][2][1][9999-12-31]
+[2][0][2][0000-00-00]
+[2][1][2][2011-01-01]
+[2][2][2][9999-12-31]
+
+FILTER(DATE) v2 <= NULL
+code=0 rows=3
+[0][3][0][NULL]
+[1][3][1][NULL]
+[2][3][2][NULL]
+
+
+DATETIME -------------------------------------------------
+
+FILTER(DATETIME) NO FILTER
+code=0 rows=9
+[0][0][0][0000-00-00 00:00:00]
+[0][1][0][2011-01-01 18:30:25]
+[0][2][0][NULL]
+[1][0][1][0000-00-00 00:00:00]
+[1][1][1][2011-01-01 18:30:25]
+[1][2][1][NULL]
+[2][0][2][0000-00-00 00:00:00]
+[2][1][2][2011-01-01 18:30:25]
+[2][2][2][NULL]
+
+FILTER(DATETIME) v2 = 0
+code=0 rows=3
+[0][0][0][0000-00-00 00:00:00]
+[1][0][1][0000-00-00 00:00:00]
+[2][0][2][0000-00-00 00:00:00]
+
+FILTER(DATETIME) v2 != 0
+code=0 rows=6
+[0][1][0][2011-01-01 18:30:25]
+[0][2][0][NULL]
+[1][1][1][2011-01-01 18:30:25]
+[1][2][1][NULL]
+[2][1][2][2011-01-01 18:30:25]
+[2][2][2][NULL]
+
+FILTER(DATETIME) v2 >= 0
+code=0 rows=6
+[0][0][0][0000-00-00 00:00:00]
+[0][1][0][2011-01-01 18:30:25]
+[1][0][1][0000-00-00 00:00:00]
+[1][1][1][2011-01-01 18:30:25]
+[2][0][2][0000-00-00 00:00:00]
+[2][1][2][2011-01-01 18:30:25]
+
+FILTER(DATETIME) v2 < 0
+code=0 rows=3
+[0][2][0][NULL]
+[1][2][1][NULL]
+[2][2][2][NULL]
+
+FILTER(DATETIME) v2 > 0
+code=0 rows=3
+[0][1][0][2011-01-01 18:30:25]
+[1][1][1][2011-01-01 18:30:25]
+[2][1][2][2011-01-01 18:30:25]
+
+FILTER(DATETIME) v2 <= 0
+code=0 rows=6
+[0][0][0][0000-00-00 00:00:00]
+[0][2][0][NULL]
+[1][0][1][0000-00-00 00:00:00]
+[1][2][1][NULL]
+[2][0][2][0000-00-00 00:00:00]
+[2][2][2][NULL]
+
+FILTER(DATETIME) v2 = 2011-01-01 18:30:25
+code=0 rows=3
+[0][1][0][2011-01-01 18:30:25]
+[1][1][1][2011-01-01 18:30:25]
+[2][1][2][2011-01-01 18:30:25]
+
+FILTER(DATETIME) v2 != 2011-01-01 18:30:25
+code=0 rows=6
+[0][0][0][0000-00-00 00:00:00]
+[0][2][0][NULL]
+[1][0][1][0000-00-00 00:00:00]
+[1][2][1][NULL]
+[2][0][2][0000-00-00 00:00:00]
+[2][2][2][NULL]
+
+FILTER(DATETIME) v2 >= 2011-01-01 18:30:25
+code=0 rows=3
+[0][1][0][2011-01-01 18:30:25]
+[1][1][1][2011-01-01 18:30:25]
+[2][1][2][2011-01-01 18:30:25]
+
+FILTER(DATETIME) v2 < 2011-01-01 18:30:25
+code=0 rows=6
+[0][0][0][0000-00-00 00:00:00]
+[0][2][0][NULL]
+[1][0][1][0000-00-00 00:00:00]
+[1][2][1][NULL]
+[2][0][2][0000-00-00 00:00:00]
+[2][2][2][NULL]
+
+FILTER(DATETIME) v2 > 2011-01-01 18:30:25
+code=0 rows=0
+
+FILTER(DATETIME) v2 <= 2011-01-01 18:30:25
+code=0 rows=9
+[0][0][0][0000-00-00 00:00:00]
+[0][1][0][2011-01-01 18:30:25]
+[0][2][0][NULL]
+[1][0][1][0000-00-00 00:00:00]
+[1][1][1][2011-01-01 18:30:25]
+[1][2][1][NULL]
+[2][0][2][0000-00-00 00:00:00]
+[2][1][2][2011-01-01 18:30:25]
+[2][2][2][NULL]
+
+FILTER(DATETIME) v2 = NULL
+code=0 rows=3
+[0][2][0][NULL]
+[1][2][1][NULL]
+[2][2][2][NULL]
+
+FILTER(DATETIME) v2 != NULL
+code=0 rows=6
+[0][0][0][0000-00-00 00:00:00]
+[0][1][0][2011-01-01 18:30:25]
+[1][0][1][0000-00-00 00:00:00]
+[1][1][1][2011-01-01 18:30:25]
+[2][0][2][0000-00-00 00:00:00]
+[2][1][2][2011-01-01 18:30:25]
+
+FILTER(DATETIME) v2 >= NULL
+code=0 rows=9
+[0][0][0][0000-00-00 00:00:00]
+[0][1][0][2011-01-01 18:30:25]
+[0][2][0][NULL]
+[1][0][1][0000-00-00 00:00:00]
+[1][1][1][2011-01-01 18:30:25]
+[1][2][1][NULL]
+[2][0][2][0000-00-00 00:00:00]
+[2][1][2][2011-01-01 18:30:25]
+[2][2][2][NULL]
+
+FILTER(DATETIME) v2 < NULL
+code=0 rows=0
+
+FILTER(DATETIME) v2 > NULL
+code=0 rows=6
+[0][0][0][0000-00-00 00:00:00]
+[0][1][0][2011-01-01 18:30:25]
+[1][0][1][0000-00-00 00:00:00]
+[1][1][1][2011-01-01 18:30:25]
+[2][0][2][0000-00-00 00:00:00]
+[2][1][2][2011-01-01 18:30:25]
+
+FILTER(DATETIME) v2 <= NULL
+code=0 rows=3
+[0][2][0][NULL]
+[1][2][1][NULL]
+[2][2][2][NULL]
+
+
+TIME -------------------------------------------------
+
+FILTER(TIME) NO FILTER
+code=0 rows=9
+[0][0][0][00:00:00]
+[0][1][0][18:30:25]
+[0][2][0][NULL]
+[1][0][1][00:00:00]
+[1][1][1][18:30:25]
+[1][2][1][NULL]
+[2][0][2][00:00:00]
+[2][1][2][18:30:25]
+[2][2][2][NULL]
+
+FILTER(TIME) v2 = 0
+code=0 rows=3
+[0][0][0][00:00:00]
+[1][0][1][00:00:00]
+[2][0][2][00:00:00]
+
+FILTER(TIME) v2 != 0
+code=0 rows=6
+[0][1][0][18:30:25]
+[0][2][0][NULL]
+[1][1][1][18:30:25]
+[1][2][1][NULL]
+[2][1][2][18:30:25]
+[2][2][2][NULL]
+
+FILTER(TIME) v2 >= 0
+code=0 rows=6
+[0][0][0][00:00:00]
+[0][1][0][18:30:25]
+[1][0][1][00:00:00]
+[1][1][1][18:30:25]
+[2][0][2][00:00:00]
+[2][1][2][18:30:25]
+
+FILTER(TIME) v2 < 0
+code=0 rows=3
+[0][2][0][NULL]
+[1][2][1][NULL]
+[2][2][2][NULL]
+
+FILTER(TIME) v2 > 0
+code=0 rows=3
+[0][1][0][18:30:25]
+[1][1][1][18:30:25]
+[2][1][2][18:30:25]
+
+FILTER(TIME) v2 <= 0
+code=0 rows=6
+[0][0][0][00:00:00]
+[0][2][0][NULL]
+[1][0][1][00:00:00]
+[1][2][1][NULL]
+[2][0][2][00:00:00]
+[2][2][2][NULL]
+
+FILTER(TIME) v2 = 18:30:25
+code=0 rows=3
+[0][1][0][18:30:25]
+[1][1][1][18:30:25]
+[2][1][2][18:30:25]
+
+FILTER(TIME) v2 != 18:30:25
+code=0 rows=6
+[0][0][0][00:00:00]
+[0][2][0][NULL]
+[1][0][1][00:00:00]
+[1][2][1][NULL]
+[2][0][2][00:00:00]
+[2][2][2][NULL]
+
+FILTER(TIME) v2 >= 18:30:25
+code=0 rows=3
+[0][1][0][18:30:25]
+[1][1][1][18:30:25]
+[2][1][2][18:30:25]
+
+FILTER(TIME) v2 < 18:30:25
+code=0 rows=6
+[0][0][0][00:00:00]
+[0][2][0][NULL]
+[1][0][1][00:00:00]
+[1][2][1][NULL]
+[2][0][2][00:00:00]
+[2][2][2][NULL]
+
+FILTER(TIME) v2 > 18:30:25
+code=0 rows=0
+
+FILTER(TIME) v2 <= 18:30:25
+code=0 rows=9
+[0][0][0][00:00:00]
+[0][1][0][18:30:25]
+[0][2][0][NULL]
+[1][0][1][00:00:00]
+[1][1][1][18:30:25]
+[1][2][1][NULL]
+[2][0][2][00:00:00]
+[2][1][2][18:30:25]
+[2][2][2][NULL]
+
+FILTER(TIME) v2 = NULL
+code=0 rows=3
+[0][2][0][NULL]
+[1][2][1][NULL]
+[2][2][2][NULL]
+
+FILTER(TIME) v2 != NULL
+code=0 rows=6
+[0][0][0][00:00:00]
+[0][1][0][18:30:25]
+[1][0][1][00:00:00]
+[1][1][1][18:30:25]
+[2][0][2][00:00:00]
+[2][1][2][18:30:25]
+
+FILTER(TIME) v2 >= NULL
+code=0 rows=9
+[0][0][0][00:00:00]
+[0][1][0][18:30:25]
+[0][2][0][NULL]
+[1][0][1][00:00:00]
+[1][1][1][18:30:25]
+[1][2][1][NULL]
+[2][0][2][00:00:00]
+[2][1][2][18:30:25]
+[2][2][2][NULL]
+
+FILTER(TIME) v2 < NULL
+code=0 rows=0
+
+FILTER(TIME) v2 > NULL
+code=0 rows=6
+[0][0][0][00:00:00]
+[0][1][0][18:30:25]
+[1][0][1][00:00:00]
+[1][1][1][18:30:25]
+[2][0][2][00:00:00]
+[2][1][2][18:30:25]
+
+FILTER(TIME) v2 <= NULL
+code=0 rows=3
+[0][2][0][NULL]
+[1][2][1][NULL]
+[2][2][2][NULL]
+
+
+YEAR(4) -------------------------------------------------
+
+FILTER(YEAR(4)) NO FILTER
+code=0 rows=8
+[1][0][1][1901]
+[1][1][1][2011]
+[1][2][1][2155]
+[1][3][1][NULL]
+[2][0][2][1901]
+[2][1][2][2011]
+[2][2][2][2155]
+[2][3][2][NULL]
+
+FILTER(YEAR(4)) v2 = 1901
+code=0 rows=2
+[1][0][1][1901]
+[2][0][2][1901]
+
+FILTER(YEAR(4)) v2 != 1901
+code=0 rows=6
+[1][1][1][2011]
+[1][2][1][2155]
+[1][3][1][NULL]
+[2][1][2][2011]
+[2][2][2][2155]
+[2][3][2][NULL]
+
+FILTER(YEAR(4)) v2 >= 1901
+code=0 rows=6
+[1][0][1][1901]
+[1][1][1][2011]
+[1][2][1][2155]
+[2][0][2][1901]
+[2][1][2][2011]
+[2][2][2][2155]
+
+FILTER(YEAR(4)) v2 < 1901
+code=0 rows=2
+[1][3][1][NULL]
+[2][3][2][NULL]
+
+FILTER(YEAR(4)) v2 > 1901
+code=0 rows=4
+[1][1][1][2011]
+[1][2][1][2155]
+[2][1][2][2011]
+[2][2][2][2155]
+
+FILTER(YEAR(4)) v2 <= 1901
+code=0 rows=4
+[1][0][1][1901]
+[1][3][1][NULL]
+[2][0][2][1901]
+[2][3][2][NULL]
+
+FILTER(YEAR(4)) v2 = 2011
+code=0 rows=2
+[1][1][1][2011]
+[2][1][2][2011]
+
+FILTER(YEAR(4)) v2 != 2011
+code=0 rows=6
+[1][0][1][1901]
+[1][2][1][2155]
+[1][3][1][NULL]
+[2][0][2][1901]
+[2][2][2][2155]
+[2][3][2][NULL]
+
+FILTER(YEAR(4)) v2 >= 2011
+code=0 rows=4
+[1][1][1][2011]
+[1][2][1][2155]
+[2][1][2][2011]
+[2][2][2][2155]
+
+FILTER(YEAR(4)) v2 < 2011
+code=0 rows=4
+[1][0][1][1901]
+[1][3][1][NULL]
+[2][0][2][1901]
+[2][3][2][NULL]
+
+FILTER(YEAR(4)) v2 > 2011
+code=0 rows=2
+[1][2][1][2155]
+[2][2][2][2155]
+
+FILTER(YEAR(4)) v2 <= 2011
+code=0 rows=6
+[1][0][1][1901]
+[1][1][1][2011]
+[1][3][1][NULL]
+[2][0][2][1901]
+[2][1][2][2011]
+[2][3][2][NULL]
+
+FILTER(YEAR(4)) v2 = 2155
+code=0 rows=2
+[1][2][1][2155]
+[2][2][2][2155]
+
+FILTER(YEAR(4)) v2 != 2155
+code=0 rows=6
+[1][0][1][1901]
+[1][1][1][2011]
+[1][3][1][NULL]
+[2][0][2][1901]
+[2][1][2][2011]
+[2][3][2][NULL]
+
+FILTER(YEAR(4)) v2 >= 2155
+code=0 rows=2
+[1][2][1][2155]
+[2][2][2][2155]
+
+FILTER(YEAR(4)) v2 < 2155
+code=0 rows=6
+[1][0][1][1901]
+[1][1][1][2011]
+[1][3][1][NULL]
+[2][0][2][1901]
+[2][1][2][2011]
+[2][3][2][NULL]
+
+FILTER(YEAR(4)) v2 > 2155
+code=0 rows=0
+
+FILTER(YEAR(4)) v2 <= 2155
+code=0 rows=8
+[1][0][1][1901]
+[1][1][1][2011]
+[1][2][1][2155]
+[1][3][1][NULL]
+[2][0][2][1901]
+[2][1][2][2011]
+[2][2][2][2155]
+[2][3][2][NULL]
+
+FILTER(YEAR(4)) v2 = NULL
+code=0 rows=2
+[1][3][1][NULL]
+[2][3][2][NULL]
+
+FILTER(YEAR(4)) v2 != NULL
+code=0 rows=6
+[1][0][1][1901]
+[1][1][1][2011]
+[1][2][1][2155]
+[2][0][2][1901]
+[2][1][2][2011]
+[2][2][2][2155]
+
+FILTER(YEAR(4)) v2 >= NULL
+code=0 rows=8
+[1][0][1][1901]
+[1][1][1][2011]
+[1][2][1][2155]
+[1][3][1][NULL]
+[2][0][2][1901]
+[2][1][2][2011]
+[2][2][2][2155]
+[2][3][2][NULL]
+
+FILTER(YEAR(4)) v2 < NULL
+code=0 rows=0
+
+FILTER(YEAR(4)) v2 > NULL
+code=0 rows=6
+[1][0][1][1901]
+[1][1][1][2011]
+[1][2][1][2155]
+[2][0][2][1901]
+[2][1][2][2011]
+[2][2][2][2155]
+
+FILTER(YEAR(4)) v2 <= NULL
+code=0 rows=2
+[1][3][1][NULL]
+[2][3][2][NULL]
+
+
+CHAR(10) -------------------------------------------------
+
+FILTER(CHAR(10)) NO FILTER
+code=0 rows=15
+[0][0][0][B
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(CHAR(10)) v2 = B
+code=0 rows=3
+[0][0][0][B
+[1][0][1][B
+[2][0][2][B
+
+FILTER(CHAR(10)) v2 != B
+code=0 rows=12
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(CHAR(10)) v2 >= B
+code=0 rows=12
+[0][0][0][B
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH]
+[1][0][1][B
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH]
+[2][0][2][B
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH]
+
+FILTER(CHAR(10)) v2 < B
+code=0 rows=3
+[0][4][0][NULL]
+[1][4][1][NULL]
+[2][4][2][NULL]
+
+FILTER(CHAR(10)) v2 > B
+code=0 rows=9
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH]
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH]
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH]
+
+FILTER(CHAR(10)) v2 <= B
+code=0 rows=6
+[0][0][0][B
+[0][4][0][NULL]
+[1][0][1][B
+[1][4][1][NULL]
+[2][0][2][B
+[2][4][2][NULL]
+
+FILTER(CHAR(10)) v2 = GI
+code=0 rows=3
+[0][1][0][GI
+[1][1][1][GI
+[2][1][2][GI
+
+FILTER(CHAR(10)) v2 != GI
+code=0 rows=12
+[0][0][0][B
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(CHAR(10)) v2 >= GI
+code=0 rows=6
+[0][1][0][GI
+[0][2][0][JHFFE
+[1][1][1][GI
+[1][2][1][JHFFE
+[2][1][2][GI
+[2][2][2][JHFFE
+
+FILTER(CHAR(10)) v2 < GI
+code=0 rows=9
+[0][0][0][B
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(CHAR(10)) v2 > GI
+code=0 rows=3
+[0][2][0][JHFFE
+[1][2][1][JHFFE
+[2][2][2][JHFFE
+
+FILTER(CHAR(10)) v2 <= GI
+code=0 rows=12
+[0][0][0][B
+[0][1][0][GI
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B
+[1][1][1][GI
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B
+[2][1][2][GI
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(CHAR(10)) v2 = JHFFE
+code=0 rows=3
+[0][2][0][JHFFE
+[1][2][1][JHFFE
+[2][2][2][JHFFE
+
+FILTER(CHAR(10)) v2 != JHFFE
+code=0 rows=12
+[0][0][0][B
+[0][1][0][GI
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B
+[1][1][1][GI
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B
+[2][1][2][GI
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(CHAR(10)) v2 >= JHFFE
+code=0 rows=3
+[0][2][0][JHFFE
+[1][2][1][JHFFE
+[2][2][2][JHFFE
+
+FILTER(CHAR(10)) v2 < JHFFE
+code=0 rows=12
+[0][0][0][B
+[0][1][0][GI
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B
+[1][1][1][GI
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B
+[2][1][2][GI
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(CHAR(10)) v2 > JHFFE
+code=0 rows=0
+
+FILTER(CHAR(10)) v2 <= JHFFE
+code=0 rows=15
+[0][0][0][B
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(CHAR(10)) v2 = FDHHDEDBHH
+code=0 rows=3
+[0][3][0][FDHHDEDBHH]
+[1][3][1][FDHHDEDBHH]
+[2][3][2][FDHHDEDBHH]
+
+FILTER(CHAR(10)) v2 != FDHHDEDBHH
+code=0 rows=12
+[0][0][0][B
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][4][0][NULL]
+[1][0][1][B
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][4][1][NULL]
+[2][0][2][B
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][4][2][NULL]
+
+FILTER(CHAR(10)) v2 >= FDHHDEDBHH
+code=0 rows=9
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH]
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH]
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH]
+
+FILTER(CHAR(10)) v2 < FDHHDEDBHH
+code=0 rows=6
+[0][0][0][B
+[0][4][0][NULL]
+[1][0][1][B
+[1][4][1][NULL]
+[2][0][2][B
+[2][4][2][NULL]
+
+FILTER(CHAR(10)) v2 > FDHHDEDBHH
+code=0 rows=6
+[0][1][0][GI
+[0][2][0][JHFFE
+[1][1][1][GI
+[1][2][1][JHFFE
+[2][1][2][GI
+[2][2][2][JHFFE
+
+FILTER(CHAR(10)) v2 <= FDHHDEDBHH
+code=0 rows=9
+[0][0][0][B
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(CHAR(10)) v2 = NULL
+code=0 rows=3
+[0][4][0][NULL]
+[1][4][1][NULL]
+[2][4][2][NULL]
+
+FILTER(CHAR(10)) v2 != NULL
+code=0 rows=12
+[0][0][0][B
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH]
+[1][0][1][B
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH]
+[2][0][2][B
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH]
+
+FILTER(CHAR(10)) v2 >= NULL
+code=0 rows=15
+[0][0][0][B
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(CHAR(10)) v2 < NULL
+code=0 rows=0
+
+FILTER(CHAR(10)) v2 > NULL
+code=0 rows=12
+[0][0][0][B
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH]
+[1][0][1][B
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH]
+[2][0][2][B
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH]
+
+FILTER(CHAR(10)) v2 <= NULL
+code=0 rows=3
+[0][4][0][NULL]
+[1][4][1][NULL]
+[2][4][2][NULL]
+
+
+VARCHAR(10) -------------------------------------------------
+
+FILTER(VARCHAR(10)) NO FILTER
+code=0 rows=15
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(VARCHAR(10)) v2 = B
+code=0 rows=3
+[0][0][0][B]
+[1][0][1][B]
+[2][0][2][B]
+
+FILTER(VARCHAR(10)) v2 != B
+code=0 rows=12
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(VARCHAR(10)) v2 >= B
+code=0 rows=12
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+
+FILTER(VARCHAR(10)) v2 < B
+code=0 rows=3
+[0][4][0][NULL]
+[1][4][1][NULL]
+[2][4][2][NULL]
+
+FILTER(VARCHAR(10)) v2 > B
+code=0 rows=9
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+
+FILTER(VARCHAR(10)) v2 <= B
+code=0 rows=6
+[0][0][0][B]
+[0][4][0][NULL]
+[1][0][1][B]
+[1][4][1][NULL]
+[2][0][2][B]
+[2][4][2][NULL]
+
+FILTER(VARCHAR(10)) v2 = GI
+code=0 rows=3
+[0][1][0][GI]
+[1][1][1][GI]
+[2][1][2][GI]
+
+FILTER(VARCHAR(10)) v2 != GI
+code=0 rows=12
+[0][0][0][B]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(VARCHAR(10)) v2 >= GI
+code=0 rows=6
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+
+FILTER(VARCHAR(10)) v2 < GI
+code=0 rows=9
+[0][0][0][B]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(VARCHAR(10)) v2 > GI
+code=0 rows=3
+[0][2][0][JHFFE]
+[1][2][1][JHFFE]
+[2][2][2][JHFFE]
+
+FILTER(VARCHAR(10)) v2 <= GI
+code=0 rows=12
+[0][0][0][B]
+[0][1][0][GI]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(VARCHAR(10)) v2 = JHFFE
+code=0 rows=3
+[0][2][0][JHFFE]
+[1][2][1][JHFFE]
+[2][2][2][JHFFE]
+
+FILTER(VARCHAR(10)) v2 != JHFFE
+code=0 rows=12
+[0][0][0][B]
+[0][1][0][GI]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(VARCHAR(10)) v2 >= JHFFE
+code=0 rows=3
+[0][2][0][JHFFE]
+[1][2][1][JHFFE]
+[2][2][2][JHFFE]
+
+FILTER(VARCHAR(10)) v2 < JHFFE
+code=0 rows=12
+[0][0][0][B]
+[0][1][0][GI]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(VARCHAR(10)) v2 > JHFFE
+code=0 rows=0
+
+FILTER(VARCHAR(10)) v2 <= JHFFE
+code=0 rows=15
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(VARCHAR(10)) v2 = FDHHDEDBHH
+code=0 rows=3
+[0][3][0][FDHHDEDBHH]
+[1][3][1][FDHHDEDBHH]
+[2][3][2][FDHHDEDBHH]
+
+FILTER(VARCHAR(10)) v2 != FDHHDEDBHH
+code=0 rows=12
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][4][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][4][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][4][2][NULL]
+
+FILTER(VARCHAR(10)) v2 >= FDHHDEDBHH
+code=0 rows=9
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+
+FILTER(VARCHAR(10)) v2 < FDHHDEDBHH
+code=0 rows=6
+[0][0][0][B]
+[0][4][0][NULL]
+[1][0][1][B]
+[1][4][1][NULL]
+[2][0][2][B]
+[2][4][2][NULL]
+
+FILTER(VARCHAR(10)) v2 > FDHHDEDBHH
+code=0 rows=6
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+
+FILTER(VARCHAR(10)) v2 <= FDHHDEDBHH
+code=0 rows=9
+[0][0][0][B]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(VARCHAR(10)) v2 = NULL
+code=0 rows=3
+[0][4][0][NULL]
+[1][4][1][NULL]
+[2][4][2][NULL]
+
+FILTER(VARCHAR(10)) v2 != NULL
+code=0 rows=12
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+
+FILTER(VARCHAR(10)) v2 >= NULL
+code=0 rows=15
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(VARCHAR(10)) v2 < NULL
+code=0 rows=0
+
+FILTER(VARCHAR(10)) v2 > NULL
+code=0 rows=12
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+
+FILTER(VARCHAR(10)) v2 <= NULL
+code=0 rows=3
+[0][4][0][NULL]
+[1][4][1][NULL]
+[2][4][2][NULL]
+
+
+BINARY(10) -------------------------------------------------
+
+FILTER(BINARY(10)) NO FILTER
+code=0 rows=15
+[0][0][0][B
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(BINARY(10)) v2 = B
+code=0 rows=3
+[0][0][0][B
+[1][0][1][B
+[2][0][2][B
+
+FILTER(BINARY(10)) v2 != B
+code=0 rows=12
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(BINARY(10)) v2 >= B
+code=0 rows=12
+[0][0][0][B
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH]
+[1][0][1][B
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH]
+[2][0][2][B
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH]
+
+FILTER(BINARY(10)) v2 < B
+code=0 rows=3
+[0][4][0][NULL]
+[1][4][1][NULL]
+[2][4][2][NULL]
+
+FILTER(BINARY(10)) v2 > B
+code=0 rows=9
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH]
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH]
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH]
+
+FILTER(BINARY(10)) v2 <= B
+code=0 rows=6
+[0][0][0][B
+[0][4][0][NULL]
+[1][0][1][B
+[1][4][1][NULL]
+[2][0][2][B
+[2][4][2][NULL]
+
+FILTER(BINARY(10)) v2 = GI
+code=0 rows=3
+[0][1][0][GI
+[1][1][1][GI
+[2][1][2][GI
+
+FILTER(BINARY(10)) v2 != GI
+code=0 rows=12
+[0][0][0][B
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(BINARY(10)) v2 >= GI
+code=0 rows=6
+[0][1][0][GI
+[0][2][0][JHFFE
+[1][1][1][GI
+[1][2][1][JHFFE
+[2][1][2][GI
+[2][2][2][JHFFE
+
+FILTER(BINARY(10)) v2 < GI
+code=0 rows=9
+[0][0][0][B
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(BINARY(10)) v2 > GI
+code=0 rows=3
+[0][2][0][JHFFE
+[1][2][1][JHFFE
+[2][2][2][JHFFE
+
+FILTER(BINARY(10)) v2 <= GI
+code=0 rows=12
+[0][0][0][B
+[0][1][0][GI
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B
+[1][1][1][GI
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B
+[2][1][2][GI
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(BINARY(10)) v2 = JHFFE
+code=0 rows=3
+[0][2][0][JHFFE
+[1][2][1][JHFFE
+[2][2][2][JHFFE
+
+FILTER(BINARY(10)) v2 != JHFFE
+code=0 rows=12
+[0][0][0][B
+[0][1][0][GI
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B
+[1][1][1][GI
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B
+[2][1][2][GI
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(BINARY(10)) v2 >= JHFFE
+code=0 rows=3
+[0][2][0][JHFFE
+[1][2][1][JHFFE
+[2][2][2][JHFFE
+
+FILTER(BINARY(10)) v2 < JHFFE
+code=0 rows=12
+[0][0][0][B
+[0][1][0][GI
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B
+[1][1][1][GI
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B
+[2][1][2][GI
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(BINARY(10)) v2 > JHFFE
+code=0 rows=0
+
+FILTER(BINARY(10)) v2 <= JHFFE
+code=0 rows=15
+[0][0][0][B
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(BINARY(10)) v2 = FDHHDEDBHH
+code=0 rows=3
+[0][3][0][FDHHDEDBHH]
+[1][3][1][FDHHDEDBHH]
+[2][3][2][FDHHDEDBHH]
+
+FILTER(BINARY(10)) v2 != FDHHDEDBHH
+code=0 rows=12
+[0][0][0][B
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][4][0][NULL]
+[1][0][1][B
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][4][1][NULL]
+[2][0][2][B
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][4][2][NULL]
+
+FILTER(BINARY(10)) v2 >= FDHHDEDBHH
+code=0 rows=9
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH]
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH]
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH]
+
+FILTER(BINARY(10)) v2 < FDHHDEDBHH
+code=0 rows=6
+[0][0][0][B
+[0][4][0][NULL]
+[1][0][1][B
+[1][4][1][NULL]
+[2][0][2][B
+[2][4][2][NULL]
+
+FILTER(BINARY(10)) v2 > FDHHDEDBHH
+code=0 rows=6
+[0][1][0][GI
+[0][2][0][JHFFE
+[1][1][1][GI
+[1][2][1][JHFFE
+[2][1][2][GI
+[2][2][2][JHFFE
+
+FILTER(BINARY(10)) v2 <= FDHHDEDBHH
+code=0 rows=9
+[0][0][0][B
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(BINARY(10)) v2 = NULL
+code=0 rows=3
+[0][4][0][NULL]
+[1][4][1][NULL]
+[2][4][2][NULL]
+
+FILTER(BINARY(10)) v2 != NULL
+code=0 rows=12
+[0][0][0][B
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH]
+[1][0][1][B
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH]
+[2][0][2][B
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH]
+
+FILTER(BINARY(10)) v2 >= NULL
+code=0 rows=15
+[0][0][0][B
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(BINARY(10)) v2 < NULL
+code=0 rows=0
+
+FILTER(BINARY(10)) v2 > NULL
+code=0 rows=12
+[0][0][0][B
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH]
+[1][0][1][B
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH]
+[2][0][2][B
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH]
+
+FILTER(BINARY(10)) v2 <= NULL
+code=0 rows=3
+[0][4][0][NULL]
+[1][4][1][NULL]
+[2][4][2][NULL]
+
+
+VARBINARY(10) -------------------------------------------------
+
+FILTER(VARBINARY(10)) NO FILTER
+code=0 rows=15
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(VARBINARY(10)) v2 = B
+code=0 rows=3
+[0][0][0][B]
+[1][0][1][B]
+[2][0][2][B]
+
+FILTER(VARBINARY(10)) v2 != B
+code=0 rows=12
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(VARBINARY(10)) v2 >= B
+code=0 rows=12
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+
+FILTER(VARBINARY(10)) v2 < B
+code=0 rows=3
+[0][4][0][NULL]
+[1][4][1][NULL]
+[2][4][2][NULL]
+
+FILTER(VARBINARY(10)) v2 > B
+code=0 rows=9
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+
+FILTER(VARBINARY(10)) v2 <= B
+code=0 rows=6
+[0][0][0][B]
+[0][4][0][NULL]
+[1][0][1][B]
+[1][4][1][NULL]
+[2][0][2][B]
+[2][4][2][NULL]
+
+FILTER(VARBINARY(10)) v2 = GI
+code=0 rows=3
+[0][1][0][GI]
+[1][1][1][GI]
+[2][1][2][GI]
+
+FILTER(VARBINARY(10)) v2 != GI
+code=0 rows=12
+[0][0][0][B]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(VARBINARY(10)) v2 >= GI
+code=0 rows=6
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+
+FILTER(VARBINARY(10)) v2 < GI
+code=0 rows=9
+[0][0][0][B]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(VARBINARY(10)) v2 > GI
+code=0 rows=3
+[0][2][0][JHFFE]
+[1][2][1][JHFFE]
+[2][2][2][JHFFE]
+
+FILTER(VARBINARY(10)) v2 <= GI
+code=0 rows=12
+[0][0][0][B]
+[0][1][0][GI]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(VARBINARY(10)) v2 = JHFFE
+code=0 rows=3
+[0][2][0][JHFFE]
+[1][2][1][JHFFE]
+[2][2][2][JHFFE]
+
+FILTER(VARBINARY(10)) v2 != JHFFE
+code=0 rows=12
+[0][0][0][B]
+[0][1][0][GI]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(VARBINARY(10)) v2 >= JHFFE
+code=0 rows=3
+[0][2][0][JHFFE]
+[1][2][1][JHFFE]
+[2][2][2][JHFFE]
+
+FILTER(VARBINARY(10)) v2 < JHFFE
+code=0 rows=12
+[0][0][0][B]
+[0][1][0][GI]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(VARBINARY(10)) v2 > JHFFE
+code=0 rows=0
+
+FILTER(VARBINARY(10)) v2 <= JHFFE
+code=0 rows=15
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(VARBINARY(10)) v2 = FDHHDEDBHH
+code=0 rows=3
+[0][3][0][FDHHDEDBHH]
+[1][3][1][FDHHDEDBHH]
+[2][3][2][FDHHDEDBHH]
+
+FILTER(VARBINARY(10)) v2 != FDHHDEDBHH
+code=0 rows=12
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][4][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][4][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][4][2][NULL]
+
+FILTER(VARBINARY(10)) v2 >= FDHHDEDBHH
+code=0 rows=9
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+
+FILTER(VARBINARY(10)) v2 < FDHHDEDBHH
+code=0 rows=6
+[0][0][0][B]
+[0][4][0][NULL]
+[1][0][1][B]
+[1][4][1][NULL]
+[2][0][2][B]
+[2][4][2][NULL]
+
+FILTER(VARBINARY(10)) v2 > FDHHDEDBHH
+code=0 rows=6
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+
+FILTER(VARBINARY(10)) v2 <= FDHHDEDBHH
+code=0 rows=9
+[0][0][0][B]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(VARBINARY(10)) v2 = NULL
+code=0 rows=3
+[0][4][0][NULL]
+[1][4][1][NULL]
+[2][4][2][NULL]
+
+FILTER(VARBINARY(10)) v2 != NULL
+code=0 rows=12
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+
+FILTER(VARBINARY(10)) v2 >= NULL
+code=0 rows=15
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][NULL]
+
+FILTER(VARBINARY(10)) v2 < NULL
+code=0 rows=0
+
+FILTER(VARBINARY(10)) v2 > NULL
+code=0 rows=12
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+
+FILTER(VARBINARY(10)) v2 <= NULL
+code=0 rows=3
+[0][4][0][NULL]
+[1][4][1][NULL]
+[2][4][2][NULL]
+
+
+CHAR(255) -------------------------------------------------
+
+FILTER(CHAR(255)) NO FILTER
+code=0 rows=24
+[0][0][0][B
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(CHAR(255)) v2 = B
+code=0 rows=3
+[0][0][0][B
+[1][0][1][B
+[2][0][2][B
+
+FILTER(CHAR(255)) v2 != B
+code=0 rows=21
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(CHAR(255)) v2 >= B
+code=0 rows=21
+[0][0][0][B
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][0][1][B
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][0][2][B
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+
+FILTER(CHAR(255)) v2 < B
+code=0 rows=3
+[0][7][0][NULL]
+[1][7][1][NULL]
+[2][7][2][NULL]
+
+FILTER(CHAR(255)) v2 > B
+code=0 rows=18
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+
+FILTER(CHAR(255)) v2 <= B
+code=0 rows=6
+[0][0][0][B
+[0][7][0][NULL]
+[1][0][1][B
+[1][7][1][NULL]
+[2][0][2][B
+[2][7][2][NULL]
+
+FILTER(CHAR(255)) v2 = GI
+code=0 rows=3
+[0][1][0][GI
+[1][1][1][GI
+[2][1][2][GI
+
+FILTER(CHAR(255)) v2 != GI
+code=0 rows=21
+[0][0][0][B
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(CHAR(255)) v2 >= GI
+code=0 rows=6
+[0][1][0][GI
+[0][2][0][JHFFE
+[1][1][1][GI
+[1][2][1][JHFFE
+[2][1][2][GI
+[2][2][2][JHFFE
+
+FILTER(CHAR(255)) v2 < GI
+code=0 rows=18
+[0][0][0][B
+[0][3][0][FDHHDEDBHH
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B
+[1][3][1][FDHHDEDBHH
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B
+[2][3][2][FDHHDEDBHH
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(CHAR(255)) v2 > GI
+code=0 rows=3
+[0][2][0][JHFFE
+[1][2][1][JHFFE
+[2][2][2][JHFFE
+
+FILTER(CHAR(255)) v2 <= GI
+code=0 rows=21
+[0][0][0][B
+[0][1][0][GI
+[0][3][0][FDHHDEDBHH
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B
+[1][1][1][GI
+[1][3][1][FDHHDEDBHH
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B
+[2][1][2][GI
+[2][3][2][FDHHDEDBHH
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(CHAR(255)) v2 = JHFFE
+code=0 rows=3
+[0][2][0][JHFFE
+[1][2][1][JHFFE
+[2][2][2][JHFFE
+
+FILTER(CHAR(255)) v2 != JHFFE
+code=0 rows=21
+[0][0][0][B
+[0][1][0][GI
+[0][3][0][FDHHDEDBHH
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B
+[1][1][1][GI
+[1][3][1][FDHHDEDBHH
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B
+[2][1][2][GI
+[2][3][2][FDHHDEDBHH
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(CHAR(255)) v2 >= JHFFE
+code=0 rows=3
+[0][2][0][JHFFE
+[1][2][1][JHFFE
+[2][2][2][JHFFE
+
+FILTER(CHAR(255)) v2 < JHFFE
+code=0 rows=21
+[0][0][0][B
+[0][1][0][GI
+[0][3][0][FDHHDEDBHH
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B
+[1][1][1][GI
+[1][3][1][FDHHDEDBHH
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B
+[2][1][2][GI
+[2][3][2][FDHHDEDBHH
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(CHAR(255)) v2 > JHFFE
+code=0 rows=0
+
+FILTER(CHAR(255)) v2 <= JHFFE
+code=0 rows=24
+[0][0][0][B
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(CHAR(255)) v2 = FDHHDEDBHH
+code=0 rows=3
+[0][3][0][FDHHDEDBHH
+[1][3][1][FDHHDEDBHH
+[2][3][2][FDHHDEDBHH
+
+FILTER(CHAR(255)) v2 != FDHHDEDBHH
+code=0 rows=21
+[0][0][0][B
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(CHAR(255)) v2 >= FDHHDEDBHH
+code=0 rows=12
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+
+FILTER(CHAR(255)) v2 < FDHHDEDBHH
+code=0 rows=12
+[0][0][0][B
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(CHAR(255)) v2 > FDHHDEDBHH
+code=0 rows=9
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+
+FILTER(CHAR(255)) v2 <= FDHHDEDBHH
+code=0 rows=15
+[0][0][0][B
+[0][3][0][FDHHDEDBHH
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B
+[1][3][1][FDHHDEDBHH
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B
+[2][3][2][FDHHDEDBHH
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(CHAR(255)) v2 = FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=0 rows=3
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+
+FILTER(CHAR(255)) v2 != FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=0 rows=21
+[0][0][0][B
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(CHAR(255)) v2 >= FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=0 rows=9
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+
+FILTER(CHAR(255)) v2 < FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=0 rows=15
+[0][0][0][B
+[0][3][0][FDHHDEDBHH
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B
+[1][3][1][FDHHDEDBHH
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B
+[2][3][2][FDHHDEDBHH
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(CHAR(255)) v2 > FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=0 rows=6
+[0][1][0][GI
+[0][2][0][JHFFE
+[1][1][1][GI
+[1][2][1][JHFFE
+[2][1][2][GI
+[2][2][2][JHFFE
+
+FILTER(CHAR(255)) v2 <= FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=0 rows=18
+[0][0][0][B
+[0][3][0][FDHHDEDBHH
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B
+[1][3][1][FDHHDEDBHH
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B
+[2][3][2][FDHHDEDBHH
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(CHAR(255)) v2 = DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=0 rows=3
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+
+FILTER(CHAR(255)) v2 != DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=0 rows=21
+[0][0][0][B
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(CHAR(255)) v2 >= DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=0 rows=15
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+
+FILTER(CHAR(255)) v2 < DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=0 rows=9
+[0][0][0][B
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(CHAR(255)) v2 > DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=0 rows=12
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+
+FILTER(CHAR(255)) v2 <= DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=0 rows=12
+[0][0][0][B
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(CHAR(255)) v2 = DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI
+code=0 rows=3
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+
+FILTER(CHAR(255)) v2 != DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI
+code=0 rows=21
+[0][0][0][B
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[0][7][0][NULL]
+[1][0][1][B
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[1][7][1][NULL]
+[2][0][2][B
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[2][7][2][NULL]
+
+FILTER(CHAR(255)) v2 >= DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI
+code=0 rows=18
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+
+FILTER(CHAR(255)) v2 < DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI
+code=0 rows=6
+[0][0][0][B
+[0][7][0][NULL]
+[1][0][1][B
+[1][7][1][NULL]
+[2][0][2][B
+[2][7][2][NULL]
+
+FILTER(CHAR(255)) v2 > DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI
+code=0 rows=15
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+
+FILTER(CHAR(255)) v2 <= DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI
+code=0 rows=9
+[0][0][0][B
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(CHAR(255)) v2 = NULL
+code=0 rows=3
+[0][7][0][NULL]
+[1][7][1][NULL]
+[2][7][2][NULL]
+
+FILTER(CHAR(255)) v2 != NULL
+code=0 rows=21
+[0][0][0][B
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][0][1][B
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][0][2][B
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+
+FILTER(CHAR(255)) v2 >= NULL
+code=0 rows=24
+[0][0][0][B
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(CHAR(255)) v2 < NULL
+code=0 rows=0
+
+FILTER(CHAR(255)) v2 > NULL
+code=0 rows=21
+[0][0][0][B
+[0][1][0][GI
+[0][2][0][JHFFE
+[0][3][0][FDHHDEDBHH
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][0][1][B
+[1][1][1][GI
+[1][2][1][JHFFE
+[1][3][1][FDHHDEDBHH
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][0][2][B
+[2][1][2][GI
+[2][2][2][JHFFE
+[2][3][2][FDHHDEDBHH
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+
+FILTER(CHAR(255)) v2 <= NULL
+code=0 rows=3
+[0][7][0][NULL]
+[1][7][1][NULL]
+[2][7][2][NULL]
+
+
+VARCHAR(255) -------------------------------------------------
+
+FILTER(VARCHAR(255)) NO FILTER
+code=0 rows=24
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(255)) v2 = B
+code=0 rows=3
+[0][0][0][B]
+[1][0][1][B]
+[2][0][2][B]
+
+FILTER(VARCHAR(255)) v2 != B
+code=0 rows=21
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(255)) v2 >= B
+code=0 rows=21
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+
+FILTER(VARCHAR(255)) v2 < B
+code=0 rows=3
+[0][7][0][NULL]
+[1][7][1][NULL]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(255)) v2 > B
+code=0 rows=18
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+
+FILTER(VARCHAR(255)) v2 <= B
+code=0 rows=6
+[0][0][0][B]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(255)) v2 = GI
+code=0 rows=3
+[0][1][0][GI]
+[1][1][1][GI]
+[2][1][2][GI]
+
+FILTER(VARCHAR(255)) v2 != GI
+code=0 rows=21
+[0][0][0][B]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(255)) v2 >= GI
+code=0 rows=6
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+
+FILTER(VARCHAR(255)) v2 < GI
+code=0 rows=18
+[0][0][0][B]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(255)) v2 > GI
+code=0 rows=3
+[0][2][0][JHFFE]
+[1][2][1][JHFFE]
+[2][2][2][JHFFE]
+
+FILTER(VARCHAR(255)) v2 <= GI
+code=0 rows=21
+[0][0][0][B]
+[0][1][0][GI]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(255)) v2 = JHFFE
+code=0 rows=3
+[0][2][0][JHFFE]
+[1][2][1][JHFFE]
+[2][2][2][JHFFE]
+
+FILTER(VARCHAR(255)) v2 != JHFFE
+code=0 rows=21
+[0][0][0][B]
+[0][1][0][GI]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(255)) v2 >= JHFFE
+code=0 rows=3
+[0][2][0][JHFFE]
+[1][2][1][JHFFE]
+[2][2][2][JHFFE]
+
+FILTER(VARCHAR(255)) v2 < JHFFE
+code=0 rows=21
+[0][0][0][B]
+[0][1][0][GI]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(255)) v2 > JHFFE
+code=0 rows=0
+
+FILTER(VARCHAR(255)) v2 <= JHFFE
+code=0 rows=24
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(255)) v2 = FDHHDEDBHH
+code=0 rows=3
+[0][3][0][FDHHDEDBHH]
+[1][3][1][FDHHDEDBHH]
+[2][3][2][FDHHDEDBHH]
+
+FILTER(VARCHAR(255)) v2 != FDHHDEDBHH
+code=0 rows=21
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(255)) v2 >= FDHHDEDBHH
+code=0 rows=12
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+
+FILTER(VARCHAR(255)) v2 < FDHHDEDBHH
+code=0 rows=12
+[0][0][0][B]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(255)) v2 > FDHHDEDBHH
+code=0 rows=9
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+
+FILTER(VARCHAR(255)) v2 <= FDHHDEDBHH
+code=0 rows=15
+[0][0][0][B]
+[0][3][0][FDHHDEDBHH]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][3][1][FDHHDEDBHH]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][3][2][FDHHDEDBHH]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(255)) v2 = FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=0 rows=3
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+
+FILTER(VARCHAR(255)) v2 != FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=0 rows=21
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(255)) v2 >= FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=0 rows=9
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+
+FILTER(VARCHAR(255)) v2 < FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=0 rows=15
+[0][0][0][B]
+[0][3][0][FDHHDEDBHH]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][3][1][FDHHDEDBHH]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][3][2][FDHHDEDBHH]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(255)) v2 > FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=0 rows=6
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+
+FILTER(VARCHAR(255)) v2 <= FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=0 rows=18
+[0][0][0][B]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(255)) v2 = DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=0 rows=3
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+
+FILTER(VARCHAR(255)) v2 != DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=0 rows=21
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(255)) v2 >= DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=0 rows=15
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+
+FILTER(VARCHAR(255)) v2 < DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=0 rows=9
+[0][0][0][B]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(255)) v2 > DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=0 rows=12
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+
+FILTER(VARCHAR(255)) v2 <= DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=0 rows=12
+[0][0][0][B]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(255)) v2 = DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI
+code=0 rows=3
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+
+FILTER(VARCHAR(255)) v2 != DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI
+code=0 rows=21
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(255)) v2 >= DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI
+code=0 rows=18
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+
+FILTER(VARCHAR(255)) v2 < DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI
+code=0 rows=6
+[0][0][0][B]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(255)) v2 > DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI
+code=0 rows=15
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+
+FILTER(VARCHAR(255)) v2 <= DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI
+code=0 rows=9
+[0][0][0][B]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(255)) v2 = NULL
+code=0 rows=3
+[0][7][0][NULL]
+[1][7][1][NULL]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(255)) v2 != NULL
+code=0 rows=21
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+
+FILTER(VARCHAR(255)) v2 >= NULL
+code=0 rows=24
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(255)) v2 < NULL
+code=0 rows=0
+
+FILTER(VARCHAR(255)) v2 > NULL
+code=0 rows=21
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGI]
+
+FILTER(VARCHAR(255)) v2 <= NULL
+code=0 rows=3
+[0][7][0][NULL]
+[1][7][1][NULL]
+[2][7][2][NULL]
+
+
+VARCHAR(511) -------------------------------------------------
+
+FILTER(VARCHAR(511)) NO FILTER
+code=0 rows=24
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(511)) v2 = B
+code=0 rows=3
+[0][0][0][B]
+[1][0][1][B]
+[2][0][2][B]
+
+FILTER(VARCHAR(511)) v2 != B
+code=0 rows=21
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[0][7][0][NULL]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][7][1][NULL]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(511)) v2 >= B
+code=0 rows=21
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+
+FILTER(VARCHAR(511)) v2 < B
+code=0 rows=3
+[0][7][0][NULL]
+[1][7][1][NULL]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(511)) v2 > B
+code=0 rows=18
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+
+FILTER(VARCHAR(511)) v2 <= B
+code=0 rows=6
+[0][0][0][B]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(511)) v2 = GI
+code=0 rows=3
+[0][1][0][GI]
+[1][1][1][GI]
+[2][1][2][GI]
+
+FILTER(VARCHAR(511)) v2 != GI
+code=0 rows=21
+[0][0][0][B]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(511)) v2 >= GI
+code=0 rows=6
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+
+FILTER(VARCHAR(511)) v2 < GI
+code=0 rows=18
+[0][0][0][B]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(511)) v2 > GI
+code=0 rows=3
+[0][2][0][JHFFE]
+[1][2][1][JHFFE]
+[2][2][2][JHFFE]
+
+FILTER(VARCHAR(511)) v2 <= GI
+code=0 rows=21
+[0][0][0][B]
+[0][1][0][GI]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(511)) v2 = JHFFE
+code=0 rows=3
+[0][2][0][JHFFE]
+[1][2][1][JHFFE]
+[2][2][2][JHFFE]
+
+FILTER(VARCHAR(511)) v2 != JHFFE
+code=0 rows=21
+[0][0][0][B]
+[0][1][0][GI]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(511)) v2 >= JHFFE
+code=0 rows=3
+[0][2][0][JHFFE]
+[1][2][1][JHFFE]
+[2][2][2][JHFFE]
+
+FILTER(VARCHAR(511)) v2 < JHFFE
+code=0 rows=21
+[0][0][0][B]
+[0][1][0][GI]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(511)) v2 > JHFFE
+code=0 rows=0
+
+FILTER(VARCHAR(511)) v2 <= JHFFE
+code=0 rows=24
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(511)) v2 = FDHHDEDBHH
+code=0 rows=3
+[0][3][0][FDHHDEDBHH]
+[1][3][1][FDHHDEDBHH]
+[2][3][2][FDHHDEDBHH]
+
+FILTER(VARCHAR(511)) v2 != FDHHDEDBHH
+code=0 rows=21
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(511)) v2 >= FDHHDEDBHH
+code=0 rows=12
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+
+FILTER(VARCHAR(511)) v2 < FDHHDEDBHH
+code=0 rows=12
+[0][0][0][B]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(511)) v2 > FDHHDEDBHH
+code=0 rows=9
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+
+FILTER(VARCHAR(511)) v2 <= FDHHDEDBHH
+code=0 rows=15
+[0][0][0][B]
+[0][3][0][FDHHDEDBHH]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][3][1][FDHHDEDBHH]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][3][2][FDHHDEDBHH]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(511)) v2 = FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=0 rows=3
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+
+FILTER(VARCHAR(511)) v2 != FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=0 rows=21
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(511)) v2 >= FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=0 rows=9
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+
+FILTER(VARCHAR(511)) v2 < FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=0 rows=15
+[0][0][0][B]
+[0][3][0][FDHHDEDBHH]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][3][1][FDHHDEDBHH]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][3][2][FDHHDEDBHH]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(511)) v2 > FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=0 rows=6
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+
+FILTER(VARCHAR(511)) v2 <= FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=0 rows=18
+[0][0][0][B]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(511)) v2 = DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=0 rows=3
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+
+FILTER(VARCHAR(511)) v2 != DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=0 rows=21
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(511)) v2 >= DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=0 rows=15
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+
+FILTER(VARCHAR(511)) v2 < DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=0 rows=9
+[0][0][0][B]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(511)) v2 > DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=0 rows=12
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+
+FILTER(VARCHAR(511)) v2 <= DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=0 rows=12
+[0][0][0][B]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(511)) v2 = DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA
+code=0 rows=3
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+
+FILTER(VARCHAR(511)) v2 != DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA
+code=0 rows=21
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(511)) v2 >= DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA
+code=0 rows=18
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+
+FILTER(VARCHAR(511)) v2 < DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA
+code=0 rows=6
+[0][0][0][B]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(511)) v2 > DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA
+code=0 rows=15
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+
+FILTER(VARCHAR(511)) v2 <= DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA
+code=0 rows=9
+[0][0][0][B]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(511)) v2 = NULL
+code=0 rows=3
+[0][7][0][NULL]
+[1][7][1][NULL]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(511)) v2 != NULL
+code=0 rows=21
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+
+FILTER(VARCHAR(511)) v2 >= NULL
+code=0 rows=24
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][7][2][NULL]
+
+FILTER(VARCHAR(511)) v2 < NULL
+code=0 rows=0
+
+FILTER(VARCHAR(511)) v2 > NULL
+code=0 rows=21
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+
+FILTER(VARCHAR(511)) v2 <= NULL
+code=0 rows=3
+[0][7][0][NULL]
+[1][7][1][NULL]
+[2][7][2][NULL]
+
+
+LONGTEXT -------------------------------------------------
+
+FILTER(LONGTEXT) NO FILTER
+code=0 rows=24
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][7][2][NULL]
+
+FILTER(LONGTEXT) v2 = B
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 != B
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 >= B
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 < B
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 > B
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 <= B
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 = GI
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 != GI
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 >= GI
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 < GI
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 > GI
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 <= GI
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 = JHFFE
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 != JHFFE
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 >= JHFFE
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 < JHFFE
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 > JHFFE
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 <= JHFFE
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 = FDHHDEDBHH
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 != FDHHDEDBHH
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 >= FDHHDEDBHH
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 < FDHHDEDBHH
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 > FDHHDEDBHH
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 <= FDHHDEDBHH
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 = FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 != FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 >= FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 < FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 > FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 <= FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 = DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 != DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 >= DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 < DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 > DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 <= DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 = DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 != DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 >= DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 < DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 > DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 <= DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA
+code=2 rows=0
+[filterblob]
+FILTER(LONGTEXT) v2 = NULL
+code=0 rows=3
+[0][7][0][NULL]
+[1][7][1][NULL]
+[2][7][2][NULL]
+
+FILTER(LONGTEXT) v2 != NULL
+code=0 rows=21
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+
+FILTER(LONGTEXT) v2 >= NULL
+code=0 rows=24
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][7][2][NULL]
+
+FILTER(LONGTEXT) v2 < NULL
+code=0 rows=0
+
+FILTER(LONGTEXT) v2 > NULL
+code=0 rows=21
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+
+FILTER(LONGTEXT) v2 <= NULL
+code=0 rows=3
+[0][7][0][NULL]
+[1][7][1][NULL]
+[2][7][2][NULL]
+
+
+LONGBLOB -------------------------------------------------
+
+FILTER(LONGBLOB) NO FILTER
+code=0 rows=24
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][7][2][NULL]
+
+FILTER(LONGBLOB) v2 = B
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 != B
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 >= B
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 < B
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 > B
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 <= B
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 = GI
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 != GI
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 >= GI
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 < GI
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 > GI
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 <= GI
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 = JHFFE
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 != JHFFE
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 >= JHFFE
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 < JHFFE
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 > JHFFE
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 <= JHFFE
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 = FDHHDEDBHH
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 != FDHHDEDBHH
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 >= FDHHDEDBHH
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 < FDHHDEDBHH
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 > FDHHDEDBHH
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 <= FDHHDEDBHH
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 = FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 != FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 >= FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 < FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 > FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 <= FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 = DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 != DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 >= DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 < DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 > DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 <= DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 = DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 != DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 >= DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 < DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 > DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 <= DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA
+code=2 rows=0
+[filterblob]
+FILTER(LONGBLOB) v2 = NULL
+code=0 rows=3
+[0][7][0][NULL]
+[1][7][1][NULL]
+[2][7][2][NULL]
+
+FILTER(LONGBLOB) v2 != NULL
+code=0 rows=21
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+
+FILTER(LONGBLOB) v2 >= NULL
+code=0 rows=24
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[0][7][0][NULL]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][7][1][NULL]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][7][2][NULL]
+
+FILTER(LONGBLOB) v2 < NULL
+code=0 rows=0
+
+FILTER(LONGBLOB) v2 > NULL
+code=0 rows=21
+[0][0][0][B]
+[0][1][0][GI]
+[0][2][0][JHFFE]
+[0][3][0][FDHHDEDBHH]
+[0][4][0][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[0][5][0][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[0][6][0][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[1][0][1][B]
+[1][1][1][GI]
+[1][2][1][JHFFE]
+[1][3][1][FDHHDEDBHH]
+[1][4][1][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[1][5][1][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[1][6][1][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+[2][0][2][B]
+[2][1][2][GI]
+[2][2][2][JHFFE]
+[2][3][2][FDHHDEDBHH]
+[2][4][2][FEFJEICICEFFADGGIEBCCGIDFJECIJHBGJGJFCCBJEBBBCAGGCHFEAAIGDIGAAIBFIHHJBGEBGDADBIIHHIJEDDDIBHIFDFIFAIF]
+[2][5][2][DIEIIDGEIGAHICBIACDFGJAJBAAECEIGIDFFHFFFDDADDIHGECGEEADDAHBAHGAHGIIAFFIHAGBDAHDCAHJHFGDJIEEBJDGDEFBHDGJGHEJDHBJDIBDAGIIBGAAHCJGFBCFEDBGDIBGACBJFDFADJEDFACDCDJCIDECEHJFBGCCBJAECGEBCBFAGEICBHAHIGGDBGEFE]
+[2][6][2][DHDIHIGFJIFCHGDCFCDAJIDDAAJCEIGDAFCGCECIADFFHJBEIBBIFICGHIAFJCGJCHEBDIBFBAEDHFEDFJAGDGIBHFJIEFHGJHCEDAIBJDHIFDEDCFDIIFAEEGABDIBHCGCJDCHJJICEFIJHDBGCGJHAJBHFHIHCCHDJJBJFDHCIAFAJHBAECAIBHGHIFCDAGDBHGJDFIHGJIAFBIEFHCEFFCDEAGBBCAAHGCBCIAJCBDBCGGJHJEGBAGCFAFGIBHDGDHDCBCEHIJJAIDDCICCAAIGBFIFGBGIAAFEJFGFEEJFDDGJGGDECECJIBIIDDFEAIAEJGCJCBFDAGEAAEBGHFJAHFABGHHGDFBGJGEJFADJIGGGDCCBHABJHADDHGFIIDDEABFDBFEHJCECBCFAAJCBEIHAIJDCGDGCGDFFHCDEJCGCGGEIFBDHADJEAAGDBCAJGDCFABCJGGJCEGHAHFJEJCCAIHFCAEBCHHEHIHEGICGFCAHJAEFHAFIEA]
+
+FILTER(LONGBLOB) v2 <= NULL
+code=0 rows=3
+[0][7][0][NULL]
+[1][7][1][NULL]
+[2][7][2][NULL]
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test19.pl b/plugin/handler_socket/regtest/test_01_lib/test19.pl
new file mode 100644
index 00000000..2e5363c8
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test19.pl
@@ -0,0 +1,190 @@
+#!/usr/bin/env perl
+
+# vim:sw=2:ai
+
+# test for filters
+
+BEGIN {
+ push @INC, "../common/";
+};
+
+use strict;
+use warnings;
+use bigint;
+use hstest;
+
+my $numeric_types = [
+ [ 'TINYINT', -128, 127 ],
+ [ 'TINYINT UNSIGNED', 0, 255 ],
+ [ 'SMALLINT', -32768, 32768 ],
+ [ 'SMALLINT UNSIGNED', 0, 65535 ],
+ [ 'MEDIUMINT', -8388608, 8388607 ],
+ [ 'MEDIUMINT UNSIGNED', 0, 16777215 ],
+ [ 'INT', -2147483648, 2147483647 ],
+ [ 'INT UNSIGNED', 0, 4294967295 ],
+ [ 'BIGINT', -9223372036854775808, 9223372036854775807 ],
+ [ 'BIGINT UNSIGNED', 0, 18446744073709551615 ],
+ [ 'FLOAT', -32768, 32768 ],
+ [ 'DOUBLE', -2147483648, 2147483647 ],
+];
+my $datetime_types = [
+ [ 'DATE', '0000-00-00', '2011-01-01', '9999-12-31' ],
+ [ 'DATETIME', 0, '2011-01-01 18:30:25' ],
+ [ 'TIME', 0, '18:30:25' ],
+ [ 'YEAR(4)', 1901, 2011, 2155 ],
+ # [ 'TIMESTAMP', 0, 999999999 ], # DOES NOT WORK YET
+];
+my $string_types = [
+ [ 'CHAR(10)', undef, 1, 2, 5, 10 ],
+ [ 'VARCHAR(10)', undef, 1, 2, 5, 10 ],
+ [ 'BINARY(10)', undef, 1, 2, 5, 10 ],
+ [ 'VARBINARY(10)', undef, 1, 2, 5, 10 ],
+ [ 'CHAR(255)', undef, 1, 2, 5, 10, 100, 200, 255 ],
+ [ 'VARCHAR(255)', undef, 1, 2, 5, 10, 100, 200, 255 ],
+ [ 'VARCHAR(511)', undef, 1, 2, 5, 10, 100, 200, 511 ],
+ [ 'LONGTEXT', 500, 1, 2, 5, 10, 100, 200, 511 ], # NOT SUPPORTED YET
+ [ 'LONGBLOB', 500, 1, 2, 5, 10, 100, 200, 511 ], # NOT SUPPORTED YET
+# [ 'VARCHAR(4096)', 500, 1, 2, 5, 10, 100, 200, 255, 256, 4095 ],
+# [ 'VARCHAR(16383)', 500, 1, 2, 5, 10, 100, 200, 255, 256, 4095, 4096, 16383 ],
+# [ 'VARBINARY(16383)', 500, 1, 2, 5, 10, 100, 200, 255, 256, 4095, 4096, 16383 ],
+];
+
+for my $rec (@$numeric_types) {
+ my ($typ, $minval, $maxval) = @$rec;
+ my @vals = ();
+ push(@vals, 0);
+ push(@vals, $maxval);
+ if ($minval != 0) {
+ push(@vals, $minval);
+ }
+ my $v1 = $minval;
+ my $v2 = $maxval;
+ for (my $i = 0; $i < 3; ++$i) {
+ $v1 /= 3;
+ $v2 /= 3;
+ push(@vals, int($v1));
+ push(@vals, int($v2));
+ }
+ my %vm = map { $_ => 1 } @vals;
+ @vals = sort { $a <=> $b } keys %vm;
+ push(@vals, undef);
+ test_one($typ, undef, \@vals);
+}
+
+for my $rec (@$datetime_types) {
+ my ($typ, @vals) = @$rec;
+ push(@vals, undef);
+ test_one($typ, undef, \@vals);
+}
+
+for my $rec (@$string_types) {
+ my ($typ, $keylen, @vs) = @$rec;
+ my @vals = ();
+ srand(999);
+ for my $len (@vs) {
+ my $s = '';
+ my @arr = ();
+ # print "$len 1\n";
+ for (my $i = 0; $i < $len; ++$i) {
+ my $v = int(rand(10));
+ $arr[$i] = chr(65 + $v);
+ }
+ # print "2\n";
+ push(@vals, join('', @arr));
+ }
+ push(@vals, undef);
+ test_one($typ, $keylen, \@vals);
+}
+
+my $hs;
+
+sub test_one {
+ my ($typ, $keylen, $values) = @_;
+ print "\n$typ -------------------------------------------------\n\n";
+ my $keylen_str = '';
+ if (defined($keylen)) {
+ $keylen_str = "($keylen)";
+ }
+ my $dbh = hstest::init_testdb();
+ my $table = 'hstesttbl';
+ my $tablesize = 3;
+ $dbh->do(
+ "create table $table " .
+ "(k1 int not null, k2 int not null, " .
+ "v1 int not null, v2 $typ default null, " .
+ "primary key (k1, k2) ) engine = innodb");
+ my $sth = $dbh->prepare("insert ignore into $table values (?,?,?,?)");
+ for (my $i = 0; $i < $tablesize; ++$i) {
+ my $j = 0;
+ for my $v (@$values) {
+ $sth->execute($i, $j, $i, $v);
+ ++$j;
+ }
+ }
+ $hs = hstest::get_hs_connection(undef, 9999);
+ my $dbname = $hstest::conf{dbname};
+ $hs->open_index(1, $dbname, $table, '', 'k1,k2,v1,v2', 'v2');
+ my $minval = $values->[0];
+ # select * ... where (k1, k2) >= ('', $minval)
+ exec_multi(
+ 4, "FILTER($typ) NO FILTER",
+ [ 1, '>=', [ '', $minval ], 1000, 0 ]
+ );
+ for my $v (@$values) {
+ my $vstr = defined($v) ? $v : 'NULL';
+ # select * ... where (k1, k2) >= ('', $minval) and v2 = $v
+ exec_multi(
+ 4, "FILTER($typ) v2 = $vstr",
+ [ 1, '>=', [ '', $minval ], 1000, 0, undef, undef, [ [ 'F', '=', 0, $v ] ] ]
+ );
+ # select * ... where (k1, k2) >= ('', $minval) and v2 != $v
+ exec_multi(
+ 4, "FILTER($typ) v2 != $vstr",
+ [ 1, '>=', [ '', $minval ], 1000, 0, undef, undef, [ [ 'F', '!=', 0, $v ] ] ]
+ );
+ # select * ... where (k1, k2) >= ('', $minval) and v2 >= $v
+ exec_multi(
+ 4, "FILTER($typ) v2 >= $vstr",
+ [ 1, '>=', [ '', $minval ], 1000, 0, undef, undef, [ [ 'F', '>=', 0, $v ] ] ]
+ );
+ # select * ... where (k1, k2) >= ('', $minval) and v2 < $v
+ exec_multi(
+ 4, "FILTER($typ) v2 < $vstr",
+ [ 1, '>=', [ '', $minval ], 1000, 0, undef, undef, [ [ 'F', '<', 0, $v ] ] ]
+ );
+ # select * ... where (k1, k2) >= ('', $minval) and v2 > $v
+ exec_multi(
+ 4, "FILTER($typ) v2 > $vstr",
+ [ 1, '>=', [ '', $minval ], 1000, 0, undef, undef, [ [ 'F', '>', 0, $v ] ] ]
+ );
+ # select * ... where (k1, k2) >= ('', $minval) and v2 <= $v
+ exec_multi(
+ 4, "FILTER($typ) v2 <= $vstr",
+ [ 1, '>=', [ '', $minval ], 1000, 0, undef, undef, [ [ 'F', '<=', 0, $v ] ] ]
+ );
+ }
+ undef $hs;
+}
+
+sub exec_multi {
+ my $width = shift(@_);
+ my $mess = shift(@_);
+ print "$mess\n";
+ my $mres = $hs->execute_multi(\@_);
+ for my $res (@$mres) {
+ my $code = shift(@$res);
+ my $nrows = $code == 0 ? scalar(@$res) / $width : 0;
+ print "code=$code rows=$nrows\n";
+ my $i = 0;
+ for my $fld (@$res) {
+ $fld = 'NULL' if !defined($fld);
+ print "[$fld]";
+ if (++$i >= $width) {
+ print "\n";
+ $i = 0;
+ }
+ }
+ print "\n";
+ }
+}
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test20.expected b/plugin/handler_socket/regtest/test_01_lib/test20.expected
new file mode 100644
index 00000000..996f6387
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test20.expected
@@ -0,0 +1,2 @@
+open_index 1st r=1
+open_index 2nd r=0
diff --git a/plugin/handler_socket/regtest/test_01_lib/test20.pl b/plugin/handler_socket/regtest/test_01_lib/test20.pl
new file mode 100644
index 00000000..96307e0a
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test20.pl
@@ -0,0 +1,33 @@
+#!/usr/bin/env perl
+
+# vim:sw=2:ai
+
+# test for a bug that table mdl is not released when open_index is failed
+
+BEGIN {
+ push @INC, "../common/";
+};
+
+use strict;
+use warnings;
+use hstest;
+
+my $dbh = hstest::init_testdb();
+my $dbname = $hstest::conf{dbname};
+my $table = 'hstesttbl';
+
+$dbh->do("drop table if exists $table");
+
+my $hs = hstest::get_hs_connection();
+my $r = $hs->open_index(1, $dbname, $table, '', 'k,v'); # fails
+print "open_index 1st r=$r\n";
+undef $hs;
+
+$dbh->do(
+ "create table $table (k varchar(30) primary key, v varchar(30) not null) " .
+ "engine = innodb");
+
+$hs = hstest::get_hs_connection();
+$r = $hs->open_index(1, $dbname, $table, '', 'k,v'); # success
+print "open_index 2nd r=$r\n";
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test21.expected b/plugin/handler_socket/regtest/test_01_lib/test21.expected
new file mode 100644
index 00000000..1d78f805
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test21.expected
@@ -0,0 +1,11 @@
+HS
+k10 v704-10
+k30 v52-30
+k40 v878-40
+k50 v682-50
+SQL
+k10 v704-10
+k30 v52-30
+k40 v878-40
+k50 v682-50
+END
diff --git a/plugin/handler_socket/regtest/test_01_lib/test21.pl b/plugin/handler_socket/regtest/test_01_lib/test21.pl
new file mode 100644
index 00000000..34e9d439
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test21.pl
@@ -0,0 +1,58 @@
+#!/usr/bin/env perl
+
+# vim:sw=2:ai
+
+# test for 'IN'
+
+BEGIN {
+ push @INC, "../common/";
+};
+
+use strict;
+use warnings;
+use hstest;
+
+my $dbh = hstest::init_testdb();
+my $table = 'hstesttbl';
+my $tablesize = 100;
+$dbh->do(
+ "create table $table (k varchar(30) primary key, v varchar(30) not null) " .
+ "engine = innodb");
+srand(999);
+
+my %valmap = ();
+
+my $sth = $dbh->prepare("insert into $table values (?,?)");
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = "k" . $i;
+ my $v = "v" . int(rand(1000)) . "-" . $i;
+ $sth->execute($k, $v);
+ $valmap{$k} = $v;
+}
+
+my $hs = hstest::get_hs_connection();
+my $dbname = $hstest::conf{dbname};
+$hs->open_index(1, $dbname, $table, '', 'k,v');
+my $vs = [ 'k10', 'k20x', 'k30', 'k40', 'k50' ];
+# select k,v from $table where k in $vs
+my $r = $hs->execute_single(1, '=', [ '' ], 10000, 0, undef, undef, undef,
+ 0, $vs);
+shift(@$r);
+print "HS\n";
+my $len = scalar(@$r) / 2;
+for (my $i = 0; $i < $len; ++$i) {
+ my $k = $r->[$i * 2];
+ my $v = $r->[$i * 2 + 1];
+ print "$k $v\n";
+}
+
+print "SQL\n";
+my $aref = $dbh->selectall_arrayref(
+ "select k,v from $table where k in ('k10', 'k20x', 'k30', 'k40', 'k50') "
+ . "order by k");
+for my $row (@$aref) {
+ my ($k, $v) = @$row;
+ print "$k $v\n";
+}
+print "END\n";
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test22.expected b/plugin/handler_socket/regtest/test_01_lib/test22.expected
new file mode 100644
index 00000000..5ad2bfae
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test22.expected
@@ -0,0 +1,9 @@
+HS
+k10 v704-10 1
+k30 v52-30 1
+k50 v682-50 1
+SQL
+k10 v704-10 1
+k30 v52-30 1
+k50 v682-50 1
+END
diff --git a/plugin/handler_socket/regtest/test_01_lib/test22.pl b/plugin/handler_socket/regtest/test_01_lib/test22.pl
new file mode 100644
index 00000000..370d16d6
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test22.pl
@@ -0,0 +1,61 @@
+#!/usr/bin/env perl
+
+# vim:sw=2:ai
+
+# test for 'IN' and filters
+
+BEGIN {
+ push @INC, "../common/";
+};
+
+use strict;
+use warnings;
+use hstest;
+
+my $dbh = hstest::init_testdb();
+my $table = 'hstesttbl';
+my $tablesize = 100;
+$dbh->do(
+ "create table $table (k varchar(30) primary key, " .
+ "v varchar(30) not null, v2 int not null) " .
+ "engine = innodb");
+srand(999);
+
+my %valmap = ();
+
+my $sth = $dbh->prepare("insert into $table values (?,?,?)");
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = "k" . $i;
+ my $v = "v" . int(rand(1000)) . "-" . $i;
+ my $v2 = ($i / 10) % 2;
+ $sth->execute($k, $v, $v2);
+ $valmap{$k} = $v;
+}
+
+my $hs = hstest::get_hs_connection();
+my $dbname = $hstest::conf{dbname};
+$hs->open_index(1, $dbname, $table, '', 'k,v,v2', 'v2');
+my $vs = [ 'k10', 'k20x', 'k30', 'k40', 'k50' ];
+# select k,v,v2 from $table where k in $vs
+my $r = $hs->execute_single(1, '=', [ '' ], 10000, 0, undef, undef,
+ [['F', '=', 0, '1']], 0, $vs);
+shift(@$r);
+print "HS\n";
+my $len = scalar(@$r) / 3;
+for (my $i = 0; $i < $len; ++$i) {
+ my $k = $r->[$i * 3];
+ my $v = $r->[$i * 3 + 1];
+ my $v2 = $r->[$i * 3 + 2];
+ print "$k $v $v2\n";
+}
+
+print "SQL\n";
+my $aref = $dbh->selectall_arrayref(
+ "select k,v,v2 from $table where k in ('k10', 'k20x', 'k30', 'k40', 'k50') "
+ . "and v2 = '1' order by k");
+for my $row (@$aref) {
+ my ($k, $v, $v2) = @$row;
+ print "$k $v $v2\n";
+}
+print "END\n";
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test23.expected b/plugin/handler_socket/regtest/test_01_lib/test23.expected
new file mode 100644
index 00000000..16ed1884
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test23.expected
@@ -0,0 +1,101 @@
+HS
+k0 v102-0 0
+k1 v635-1 0
+k10 MOD 1
+k11 v751-11 1
+k12 v367-12 1
+k13 v400-13 1
+k14 v397-14 1
+k15 v170-15 1
+k16 v719-16 1
+k17 v734-17 1
+k18 v587-18 1
+k19 v494-19 1
+k2 v803-2 0
+k20 v523-20 0
+k21 v954-21 0
+k22 v433-22 0
+k23 v820-23 0
+k24 v283-24 0
+k25 v837-25 0
+k26 v205-26 0
+k27 v415-27 0
+k28 v545-28 0
+k29 v583-29 0
+k3 v925-3 0
+k30 MOD 1
+k31 v323-31 1
+k32 v614-32 1
+k33 v679-33 1
+k34 v805-34 1
+k35 v451-35 1
+k36 v115-36 1
+k37 v269-37 1
+k38 v218-38 1
+k39 v617-39 1
+k4 v775-4 0
+k40 v878-40 0
+k41 v345-41 0
+k42 v512-42 0
+k43 v969-43 0
+k44 v408-44 0
+k45 v291-45 0
+k46 v858-46 0
+k47 v953-47 0
+k48 v710-48 0
+k49 v142-49 0
+k5 v537-5 0
+k50 MOD 1
+k51 v934-51 1
+k52 v621-52 1
+k53 v965-53 1
+k54 v574-54 1
+k55 v204-55 1
+k56 v298-56 1
+k57 v134-57 1
+k58 v983-58 1
+k59 v444-59 1
+k6 v592-6 0
+k60 v144-60 0
+k61 v152-61 0
+k62 v187-62 0
+k63 v215-63 0
+k64 v8-64 0
+k65 v697-65 0
+k66 v651-66 0
+k67 v280-67 0
+k68 v701-68 0
+k69 v537-69 0
+k7 v414-7 0
+k70 v413-70 1
+k71 v69-71 1
+k72 v86-72 1
+k73 v822-73 1
+k74 v670-74 1
+k75 v370-75 1
+k76 v806-76 1
+k77 v688-77 1
+k78 v26-78 1
+k79 v66-79 1
+k8 v590-8 0
+k80 v802-80 0
+k81 v171-81 0
+k82 v557-82 0
+k83 v847-83 0
+k84 v777-84 0
+k85 v730-85 0
+k86 v987-86 0
+k87 v115-87 0
+k88 v646-88 0
+k89 v496-89 0
+k9 v302-9 0
+k90 v120-90 1
+k91 v684-91 1
+k92 v374-92 1
+k93 v65-93 1
+k94 v370-94 1
+k95 v174-95 1
+k96 v828-96 1
+k97 v867-97 1
+k98 v759-98 1
+k99 v703-99 1
diff --git a/plugin/handler_socket/regtest/test_01_lib/test23.pl b/plugin/handler_socket/regtest/test_01_lib/test23.pl
new file mode 100644
index 00000000..d9bd0381
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test23.pl
@@ -0,0 +1,53 @@
+#!/usr/bin/env perl
+
+# vim:sw=2:ai
+
+# test for 'IN', filters, and modifications
+
+BEGIN {
+ push @INC, "../common/";
+};
+
+use strict;
+use warnings;
+use hstest;
+
+my $dbh = hstest::init_testdb();
+my $table = 'hstesttbl';
+my $tablesize = 100;
+$dbh->do(
+ "create table $table (k varchar(30) primary key, " .
+ "v varchar(30) not null, v2 int not null) " .
+ "engine = innodb");
+srand(999);
+
+my %valmap = ();
+
+my $sth = $dbh->prepare("insert into $table values (?,?,?)");
+for (my $i = 0; $i < $tablesize; ++$i) {
+ my $k = "k" . $i;
+ my $v = "v" . int(rand(1000)) . "-" . $i;
+ my $v2 = ($i / 10) % 2;
+ $sth->execute($k, $v, $v2);
+ $valmap{$k} = $v;
+}
+
+my $hs = hstest::get_hs_connection(undef, 9999);
+my $dbname = $hstest::conf{dbname};
+$hs->open_index(1, $dbname, $table, '', 'k,v,v2', 'v2');
+$hs->open_index(2, $dbname, $table, '', 'v', 'v2');
+my $vs = [ 'k10', 'k20x', 'k30', 'k40', 'k50' ];
+# update $table set v = 'MOD' where k in $vs and v2 = '1'
+my $r = $hs->execute_single(2, '=', [ '' ], 10000, 0, 'U', [ 'MOD' ],
+ [['F', '=', 0, '1']], 0, $vs);
+$r = $hs->execute_single(1, '>=', [ '' ], 10000, 0);
+shift(@$r);
+print "HS\n";
+my $len = scalar(@$r) / 3;
+for (my $i = 0; $i < $len; ++$i) {
+ my $k = $r->[$i * 3];
+ my $v = $r->[$i * 3 + 1];
+ my $v2 = $r->[$i * 3 + 2];
+ print "$k $v $v2\n";
+}
+
diff --git a/plugin/handler_socket/regtest/test_01_lib/test24.expected b/plugin/handler_socket/regtest/test_01_lib/test24.expected
new file mode 100644
index 00000000..5d07e01b
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test24.expected
@@ -0,0 +1,2 @@
+HS
+0 0
diff --git a/plugin/handler_socket/regtest/test_01_lib/test24.pl b/plugin/handler_socket/regtest/test_01_lib/test24.pl
new file mode 100644
index 00000000..f4e3bb3f
--- /dev/null
+++ b/plugin/handler_socket/regtest/test_01_lib/test24.pl
@@ -0,0 +1,35 @@
+#!/usr/bin/env perl
+
+# vim:sw=2:ai
+
+# test for issue #78
+
+BEGIN {
+ push @INC, "../common/";
+};
+
+use strict;
+use warnings;
+use hstest;
+
+my $dbh = hstest::init_testdb();
+my $table = 'hstesttbl';
+my $tablesize = 100;
+$dbh->do(
+ "create table $table (" .
+ "id bigint(20) not null auto_increment, " .
+ "t1 timestamp not null default current_timestamp, " .
+ "primary key (id)" .
+ ") engine = innodb");
+srand(999);
+
+my %valmap = ();
+
+my $hs = hstest::get_hs_connection(undef, 9999);
+my $dbname = $hstest::conf{dbname};
+$hs->open_index(0, $dbname, $table, 'PRIMARY', 'id,t1');
+my $res = $hs->execute_single(0, '+', [ 321 ], 0, 0);
+die $hs->get_error() if $res->[0] != 0;
+print "HS\n";
+print join(' ', @$res) . "\n";
+
diff --git a/plugin/locale_info/CMakeLists.txt b/plugin/locale_info/CMakeLists.txt
new file mode 100644
index 00000000..c988d652
--- /dev/null
+++ b/plugin/locale_info/CMakeLists.txt
@@ -0,0 +1,4 @@
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql ${CMAKE_SOURCE_DIR}/regex)
+
+MYSQL_ADD_PLUGIN(LOCALES locale_info.cc RECOMPILE_FOR_EMBEDDED)
+
diff --git a/plugin/locale_info/locale_info.cc b/plugin/locale_info/locale_info.cc
new file mode 100644
index 00000000..dd0ca303
--- /dev/null
+++ b/plugin/locale_info/locale_info.cc
@@ -0,0 +1,121 @@
+/*
+ Copyright (c) 2013, Spaempresarial - Brazil, Roberto Spadim
+ http://www.spadim.com.br/
+ roberto@spadim.com.br
+
+ 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 Roberto Spadim nor the
+ names of the 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 ROBERTO SPADIM 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.
+ */
+
+#include <my_global.h>
+#include <sql_class.h> // THD
+#include <sql_i_s.h> // ST_SCHEMA_TABLE
+#include <mysql/plugin.h>
+#include <m_ctype.h>
+#include "sql_locale.h"
+
+static MY_LOCALE **locale_list;
+
+namespace Show {
+
+/* LOCALES */
+static ST_FIELD_INFO locale_info_locale_fields_info[]=
+{
+ Column("ID", SLonglong(4), NOT_NULL, "Id"),
+ Column("NAME", Varchar(255), NOT_NULL, "Name"),
+ Column("DESCRIPTION", Varchar(255), NOT_NULL, "Description"),
+ Column("MAX_MONTH_NAME_LENGTH", SLonglong(4), NOT_NULL),
+ Column("MAX_DAY_NAME_LENGTH", SLonglong(4), NOT_NULL),
+ Column("DECIMAL_POINT", Varchar(2), NOT_NULL),
+ Column("THOUSAND_SEP", Varchar(2), NOT_NULL),
+ Column("ERROR_MESSAGE_LANGUAGE", Varchar(64), NOT_NULL, "Error_Message_Language"),
+ CEnd()
+};
+
+} // namespace Show
+
+static int locale_info_fill_table_locale(THD* thd, TABLE_LIST* tables, COND* cond)
+{
+ TABLE *table= tables->table;
+ CHARSET_INFO *cs= system_charset_info;
+
+ for (MY_LOCALE **loc= locale_list; *loc; loc++)
+ {
+ /* ID */
+ table->field[0]->store((longlong) (*loc)->number, TRUE);
+ /* NAME */
+ table->field[1]->store((*loc)->name, strlen((*loc)->name), cs);
+ /* DESCRIPTION */
+ table->field[2]->store((*loc)->description, strlen((*loc)->description), cs);
+ /* MAX_MONTH_NAME_LENGTH */
+ table->field[3]->store((longlong) (*loc)->max_month_name_length, TRUE);
+ /* MAX_DAY_NAME_LENGTH */
+ table->field[4]->store((longlong) (*loc)->max_day_name_length, TRUE);
+ /* DECIMAL_POINT */
+ char decimal= (*loc)->decimal_point;
+ table->field[5]->store(&decimal, decimal ? 1 : 0, cs);
+ /* THOUSAND_SEP */
+ char thousand= (*loc)->thousand_sep;
+ table->field[6]->store(&thousand, thousand ? 1 : 0, cs);
+ /* ERROR_MESSAGE_LANGUAGE */
+ table->field[7]->store((*loc)->errmsgs->language,
+ strlen((*loc)->errmsgs->language), cs);
+ if (schema_table_store_record(thd, table))
+ return 1;
+ }
+ return 0;
+}
+
+static int locale_info_plugin_init_locales(void *p)
+{
+ ST_SCHEMA_TABLE *schema= (ST_SCHEMA_TABLE *)p;
+ schema->fields_info= Show::locale_info_locale_fields_info;
+ schema->fill_table= locale_info_fill_table_locale;
+
+ locale_list = my_locales;
+
+ return 0;
+}
+static struct st_mysql_information_schema locale_info_plugin=
+{ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+/*
+ Plugin library descriptor
+*/
+
+maria_declare_plugin(locales)
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN, /* the plugin type (see include/mysql/plugin.h) */
+ &locale_info_plugin, /* pointer to type-specific plugin descriptor */
+ "LOCALES", /* plugin name */
+ "Roberto Spadim, Spaempresarial - Brazil", /* plugin author */
+ "Lists all locales from server.", /* the plugin description */
+ PLUGIN_LICENSE_BSD, /* the plugin license (see include/mysql/plugin.h) */
+ locale_info_plugin_init_locales, /* Pointer to plugin initialization function */
+ 0, /* Pointer to plugin deinitialization function */
+ 0x0100, /* Numeric version 0xAABB means AA.BB version */
+ NULL, /* Status variables */
+ NULL, /* System variables */
+ "1.0", /* String version representation */
+ MariaDB_PLUGIN_MATURITY_STABLE /* Maturity (see include/mysql/plugin.h)*/
+}
+maria_declare_plugin_end;
diff --git a/plugin/metadata_lock_info/CMakeLists.txt b/plugin/metadata_lock_info/CMakeLists.txt
new file mode 100644
index 00000000..6b1f5108
--- /dev/null
+++ b/plugin/metadata_lock_info/CMakeLists.txt
@@ -0,0 +1,3 @@
+SET(METADATA_LOCK_INFO_SOURCES metadata_lock_info.cc)
+MYSQL_ADD_PLUGIN(metadata_lock_info ${METADATA_LOCK_INFO_SOURCES}
+ RECOMPILE_FOR_EMBEDDED)
diff --git a/plugin/metadata_lock_info/metadata_lock_info.cc b/plugin/metadata_lock_info/metadata_lock_info.cc
new file mode 100644
index 00000000..a85048de
--- /dev/null
+++ b/plugin/metadata_lock_info/metadata_lock_info.cc
@@ -0,0 +1,144 @@
+/* Copyright (C) 2013 Kentoku Shiba
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#define MYSQL_SERVER 1
+#include <my_global.h>
+#include "mysql_version.h"
+#include "mysql/plugin.h"
+#include "sql_class.h"
+#include "sql_i_s.h"
+
+static const LEX_STRING metadata_lock_info_lock_name[] = {
+ { C_STRING_WITH_LEN("Backup lock") },
+ { C_STRING_WITH_LEN("Schema metadata lock") },
+ { C_STRING_WITH_LEN("Table metadata lock") },
+ { C_STRING_WITH_LEN("Stored function metadata lock") },
+ { C_STRING_WITH_LEN("Stored procedure metadata lock") },
+ { C_STRING_WITH_LEN("Stored package body metadata lock") },
+ { C_STRING_WITH_LEN("Trigger metadata lock") },
+ { C_STRING_WITH_LEN("Event metadata lock") },
+ { C_STRING_WITH_LEN("User lock") },
+};
+
+namespace Show {
+
+static ST_FIELD_INFO i_s_metadata_lock_info_fields_info[] =
+{
+ Column("THREAD_ID", ULonglong(20), NOT_NULL, "thread_id"),
+ Column("LOCK_MODE", Varchar(24), NULLABLE, "lock_mode"),
+ Column("LOCK_DURATION", Varchar(30), NULLABLE, "lock_duration"),
+ Column("LOCK_TYPE", Varchar(33), NULLABLE, "lock_type"),
+ Column("TABLE_SCHEMA", Name(), NULLABLE, "table_schema"),
+ Column("TABLE_NAME", Name(), NULLABLE, "table_name"),
+ CEnd()
+};
+
+} // namespace Show
+
+
+struct st_i_s_metadata_param
+{
+ THD *thd;
+ TABLE *table;
+};
+
+int i_s_metadata_lock_info_fill_row(
+ MDL_ticket *mdl_ticket,
+ void *arg,
+ bool granted
+) {
+ st_i_s_metadata_param *param = (st_i_s_metadata_param *) arg;
+ THD *thd = param->thd;
+ TABLE *table = param->table;
+ DBUG_ENTER("i_s_metadata_lock_info_fill_row");
+ MDL_context *mdl_ctx = mdl_ticket->get_ctx();
+ MDL_key *mdl_key = mdl_ticket->get_key();
+ MDL_key::enum_mdl_namespace mdl_namespace = mdl_key->mdl_namespace();
+ if (!granted)
+ DBUG_RETURN(0);
+ table->field[0]->store((longlong) mdl_ctx->get_thread_id(), TRUE);
+ table->field[1]->set_notnull();
+ table->field[1]->store(mdl_ticket->get_type_name(), system_charset_info);
+ table->field[2]->set_null();
+ table->field[3]->set_notnull();
+ table->field[3]->store(
+ metadata_lock_info_lock_name[(int) mdl_namespace].str,
+ metadata_lock_info_lock_name[(int) mdl_namespace].length,
+ system_charset_info);
+ table->field[4]->set_notnull();
+ table->field[4]->store(mdl_key->db_name(),
+ mdl_key->db_name_length(), system_charset_info);
+ table->field[5]->set_notnull();
+ table->field[5]->store(mdl_key->name(),
+ mdl_key->name_length(), system_charset_info);
+ if (schema_table_store_record(thd, table))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+}
+
+int i_s_metadata_lock_info_fill_table(
+ THD *thd,
+ TABLE_LIST *tables,
+ COND *cond
+) {
+ st_i_s_metadata_param param;
+ DBUG_ENTER("i_s_metadata_lock_info_fill_table");
+ param.table = tables->table;
+ param.thd = thd;
+ DBUG_RETURN(mdl_iterate(i_s_metadata_lock_info_fill_row, &param));
+}
+
+static int i_s_metadata_lock_info_init(
+ void *p
+) {
+
+ compile_time_assert(sizeof(metadata_lock_info_lock_name)/sizeof(LEX_STRING)
+ == MDL_key::NAMESPACE_END);
+
+ ST_SCHEMA_TABLE *schema = (ST_SCHEMA_TABLE *) p;
+ DBUG_ENTER("i_s_metadata_lock_info_init");
+ schema->fields_info = Show::i_s_metadata_lock_info_fields_info;
+ schema->fill_table = i_s_metadata_lock_info_fill_table;
+ schema->idx_field1 = 0;
+ DBUG_RETURN(0);
+}
+
+static int i_s_metadata_lock_info_deinit(
+ void *p
+) {
+ DBUG_ENTER("i_s_metadata_lock_info_deinit");
+ DBUG_RETURN(0);
+}
+
+static struct st_mysql_information_schema i_s_metadata_lock_info_plugin =
+{ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+maria_declare_plugin(metadata_lock_info)
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &i_s_metadata_lock_info_plugin,
+ "METADATA_LOCK_INFO",
+ "Kentoku Shiba",
+ "Metadata locking viewer",
+ PLUGIN_LICENSE_GPL,
+ i_s_metadata_lock_info_init,
+ i_s_metadata_lock_info_deinit,
+ 0x0001,
+ NULL,
+ NULL,
+ NULL,
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
diff --git a/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/global_read_lock.result b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/global_read_lock.result
new file mode 100644
index 00000000..12afd501
--- /dev/null
+++ b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/global_read_lock.result
@@ -0,0 +1,9 @@
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
+lock_mode lock_duration lock_type table_schema table_name
+FLUSH TABLES WITH READ LOCK;
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
+lock_mode lock_duration lock_type table_schema table_name
+MDL_BACKUP_FTWRL2 NULL Backup lock
+UNLOCK TABLES;
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
+lock_mode lock_duration lock_type table_schema table_name
diff --git a/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/table_metadata_lock.result b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/table_metadata_lock.result
new file mode 100644
index 00000000..1b76b9e8
--- /dev/null
+++ b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/table_metadata_lock.result
@@ -0,0 +1,13 @@
+CREATE TABLE IF NOT EXISTS t1(a int);
+BEGIN;
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
+lock_mode lock_duration lock_type table_schema table_name
+SELECT * FROM t1;
+a
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
+lock_mode lock_duration lock_type table_schema table_name
+MDL_SHARED_READ NULL Table metadata lock test t1
+ROLLBACK;
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
+lock_mode lock_duration lock_type table_schema table_name
+DROP TABLE t1;
diff --git a/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/user_lock.result b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/user_lock.result
new file mode 100644
index 00000000..34d238cb
--- /dev/null
+++ b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/r/user_lock.result
@@ -0,0 +1,13 @@
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
+lock_mode lock_duration lock_type table_schema table_name
+SELECT GET_LOCK('LOCK1',0);
+GET_LOCK('LOCK1',0)
+1
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
+lock_mode lock_duration lock_type table_schema table_name
+MDL_SHARED_NO_WRITE NULL User lock LOCK1
+SELECT RELEASE_LOCK('LOCK1');
+RELEASE_LOCK('LOCK1')
+1
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
+lock_mode lock_duration lock_type table_schema table_name
diff --git a/plugin/metadata_lock_info/mysql-test/metadata_lock_info/suite.opt b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/suite.opt
new file mode 100644
index 00000000..47a7881b
--- /dev/null
+++ b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/suite.opt
@@ -0,0 +1,2 @@
+--loose-metadata_lock_info
+--plugin-load-add=$METADATA_LOCK_INFO_SO
diff --git a/plugin/metadata_lock_info/mysql-test/metadata_lock_info/suite.pm b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/suite.pm
new file mode 100644
index 00000000..a1c6d003
--- /dev/null
+++ b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/suite.pm
@@ -0,0 +1,11 @@
+package My::Suite::Metadata_lock_info;
+
+@ISA = qw(My::Suite);
+
+return "No Metadata_lock_info plugin" unless $ENV{METADATA_LOCK_INFO_SO} or
+ $::mysqld_variables{'metadata-lock-info'} eq "ON";;
+
+sub is_default { 1 }
+
+bless { };
+
diff --git a/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/global_read_lock.test b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/global_read_lock.test
new file mode 100644
index 00000000..103050e3
--- /dev/null
+++ b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/global_read_lock.test
@@ -0,0 +1,6 @@
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
+FLUSH TABLES WITH READ LOCK;
+--sorted_result
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
+UNLOCK TABLES;
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
diff --git a/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/table_metadata_lock.test b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/table_metadata_lock.test
new file mode 100644
index 00000000..3451dff0
--- /dev/null
+++ b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/table_metadata_lock.test
@@ -0,0 +1,8 @@
+CREATE TABLE IF NOT EXISTS t1(a int);
+BEGIN;
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
+SELECT * FROM t1;
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
+ROLLBACK;
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
+DROP TABLE t1;
diff --git a/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/user_lock.test b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/user_lock.test
new file mode 100644
index 00000000..85dec3dc
--- /dev/null
+++ b/plugin/metadata_lock_info/mysql-test/metadata_lock_info/t/user_lock.test
@@ -0,0 +1,5 @@
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
+SELECT GET_LOCK('LOCK1',0);
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
+SELECT RELEASE_LOCK('LOCK1');
+SELECT lock_mode, lock_duration, lock_type, table_schema, table_name FROM information_schema.metadata_lock_info;
diff --git a/plugin/qc_info/CMakeLists.txt b/plugin/qc_info/CMakeLists.txt
new file mode 100644
index 00000000..b8c5f926
--- /dev/null
+++ b/plugin/qc_info/CMakeLists.txt
@@ -0,0 +1,4 @@
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql
+ ${PCRE_INCLUDES})
+
+MYSQL_ADD_PLUGIN(QUERY_CACHE_INFO qc_info.cc RECOMPILE_FOR_EMBEDDED)
diff --git a/plugin/qc_info/qc_info.cc b/plugin/qc_info/qc_info.cc
new file mode 100644
index 00000000..41b3c7b4
--- /dev/null
+++ b/plugin/qc_info/qc_info.cc
@@ -0,0 +1,316 @@
+/*
+ Copyright (c) 2008, Roland Bouman
+ http://rpbouman.blogspot.com/
+ roland.bouman@gmail.com
+ 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 Roland Bouman nor the
+ names of the 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 <COPYRIGHT HOLDER> 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.
+ */
+
+
+#ifndef MYSQL_SERVER
+#define MYSQL_SERVER
+#endif
+
+#include <my_global.h>
+#include <sql_parse.h> // check_global_access
+#include <sql_acl.h> // PROCESS_ACL
+#include <sql_class.h> // THD
+#include <sql_cache.h>
+#include <sql_i_s.h> // ST_SCHEMA_TABLE
+#include <set_var.h> // sql_mode_string_representation
+#include <tztime.h>
+#include <mysql/plugin.h>
+
+class Accessible_Query_Cache : public Query_cache {
+public:
+ HASH *get_queries()
+ {
+ return &this->queries;
+ }
+} *qc;
+
+bool schema_table_store_record(THD *thd, TABLE *table);
+
+#define MAX_STATEMENT_TEXT_LENGTH 32767
+#define COLUMN_STATEMENT_SCHEMA 0
+#define COLUMN_STATEMENT_TEXT 1
+#define COLUMN_RESULT_BLOCKS_COUNT 2
+#define COLUMN_RESULT_BLOCKS_SIZE 3
+#define COLUMN_RESULT_BLOCKS_SIZE_USED 4
+#define COLUMN_LIMIT 5
+#define COLUMN_MAX_SORT_LENGTH 6
+#define COLUMN_GROUP_CONCAT_MAX_LENGTH 7
+#define COLUMN_CHARACTER_SET_CLIENT 8
+#define COLUMN_CHARACTER_SET_RESULT 9
+#define COLUMN_COLLATION 10
+#define COLUMN_TIMEZONE 11
+#define COLUMN_DEFAULT_WEEK_FORMAT 12
+#define COLUMN_DIV_PRECISION_INCREMENT 13
+#define COLUMN_SQL_MODE 14
+#define COLUMN_LC_TIME_NAMES 15
+
+#define COLUMN_CLIENT_LONG_FLAG 16
+#define COLUMN_CLIENT_PROTOCOL_41 17
+#define COLUMN_PROTOCOL_TYPE 18
+#define COLUMN_MORE_RESULTS_EXISTS 19
+#define COLUMN_IN_TRANS 20
+#define COLUMN_AUTOCOMMIT 21
+#define COLUMN_PKT_NR 22
+#define COLUMN_HITS 23
+
+
+namespace Show {
+
+/* ST_FIELD_INFO is defined in table.h */
+static ST_FIELD_INFO qc_info_fields[]=
+{
+ Column("STATEMENT_SCHEMA", Varchar(NAME_LEN), NOT_NULL),
+ Column("STATEMENT_TEXT", Longtext(MAX_STATEMENT_TEXT_LENGTH),NOT_NULL),
+ Column("RESULT_BLOCKS_COUNT", SLong(), NOT_NULL),
+ Column("RESULT_BLOCKS_SIZE", SLonglong(MY_INT32_NUM_DECIMAL_DIGITS),NOT_NULL),
+ Column("RESULT_BLOCKS_SIZE_USED",SLonglong(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL),
+ Column("LIMIT", SLonglong(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL),
+ Column("MAX_SORT_LENGTH", SLonglong(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL),
+ Column("GROUP_CONCAT_MAX_LENGTH",SLonglong(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL),
+ Column("CHARACTER_SET_CLIENT", CSName(), NOT_NULL),
+ Column("CHARACTER_SET_RESULT", CSName(), NOT_NULL),
+ Column("COLLATION", CSName(), NOT_NULL),
+ Column("TIMEZONE", Varchar(50), NOT_NULL),
+ Column("DEFAULT_WEEK_FORMAT", SLong(), NOT_NULL),
+ Column("DIV_PRECISION_INCREMENT",SLong(), NOT_NULL),
+ Column("SQL_MODE", Varchar(250), NOT_NULL),
+ Column("LC_TIME_NAMES", Varchar(100), NOT_NULL),
+ Column("CLIENT_LONG_FLAG", STiny(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL),
+ Column("CLIENT_PROTOCOL_41", STiny(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL),
+ Column("PROTOCOL_TYPE", STiny(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL),
+ Column("MORE_RESULTS_EXISTS", STiny(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL),
+ Column("IN_TRANS", STiny(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL),
+ Column("AUTOCOMMIT", STiny(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL),
+ Column("PACKET_NUMBER", STiny(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL),
+ Column("HITS", SLonglong(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL),
+ CEnd()
+};
+
+} // namespace Show
+
+
+static const char unknown[]= "#UNKNOWN#";
+
+static int qc_info_fill_table(THD *thd, TABLE_LIST *tables,
+ COND *cond)
+{
+ int status= 1;
+ CHARSET_INFO *scs= system_charset_info;
+ TABLE *table= tables->table;
+ HASH *queries = qc->get_queries();
+
+ /* one must have PROCESS privilege to see others' queries */
+ if (check_global_access(thd, PROCESS_ACL, true))
+ return 0;
+
+ if (qc->try_lock(thd))
+ return 0; // QC is or is being disabled
+
+ /* loop through all queries in the query cache */
+ for (uint i= 0; i < queries->records; i++)
+ {
+ const uchar *query_cache_block_raw;
+ Query_cache_block* query_cache_block;
+ Query_cache_query* query_cache_query;
+ Query_cache_query_flags flags;
+ uint result_blocks_count;
+ ulonglong result_blocks_size;
+ ulonglong result_blocks_size_used;
+ Query_cache_block *first_result_block;
+ Query_cache_block *result_block;
+ const char *statement_text;
+ size_t statement_text_length;
+ size_t flags_length;
+ const char *key, *db;
+ size_t key_length, db_length;
+ LEX_CSTRING sql_mode_str;
+ const String *tz;
+ CHARSET_INFO *cs_client;
+ CHARSET_INFO *cs_result;
+ CHARSET_INFO *collation;
+
+ query_cache_block_raw = my_hash_element(queries, i);
+ query_cache_block = (Query_cache_block*)query_cache_block_raw;
+ if (unlikely(!query_cache_block ||
+ query_cache_block->type != Query_cache_block::QUERY))
+ continue;
+
+ query_cache_query = query_cache_block->query();
+
+ /* Get the actual SQL statement for this query cache query */
+ statement_text = (const char*)query_cache_query->query();
+ statement_text_length = strlen(statement_text);
+ /* We truncate SQL statements up to MAX_STATEMENT_TEXT_LENGTH in our I_S table */
+ table->field[COLUMN_STATEMENT_TEXT]->store((char*)statement_text,
+ MY_MIN(statement_text_length, MAX_STATEMENT_TEXT_LENGTH), scs);
+
+ /* get the entire key that identifies this query cache query */
+ key = (const char*)query_cache_query_get_key(query_cache_block_raw,
+ &key_length, 0);
+ /* get and store the flags */
+ flags_length= key_length - QUERY_CACHE_FLAGS_SIZE;
+ memcpy(&flags, key+flags_length, QUERY_CACHE_FLAGS_SIZE);
+ table->field[COLUMN_LIMIT]->store(flags.limit, 0);
+ table->field[COLUMN_MAX_SORT_LENGTH]->store(flags.max_sort_length, 0);
+ table->field[COLUMN_GROUP_CONCAT_MAX_LENGTH]->store(flags.group_concat_max_len, 0);
+
+ cs_client= get_charset(flags.character_set_client_num, MYF(MY_WME));
+ if (likely(cs_client))
+ table->field[COLUMN_CHARACTER_SET_CLIENT]->
+ store(cs_client->csname, strlen(cs_client->csname), scs);
+ else
+ table->field[COLUMN_CHARACTER_SET_CLIENT]->
+ store(STRING_WITH_LEN(unknown), scs);
+
+ cs_result= get_charset(flags.character_set_results_num, MYF(MY_WME));
+ if (likely(cs_result))
+ table->field[COLUMN_CHARACTER_SET_RESULT]->
+ store(cs_result->csname, strlen(cs_result->csname), scs);
+ else
+ table->field[COLUMN_CHARACTER_SET_RESULT]->
+ store(STRING_WITH_LEN(unknown), scs);
+
+ collation= get_charset(flags.collation_connection_num, MYF(MY_WME));
+ if (likely(collation))
+ table->field[COLUMN_COLLATION]->
+ store(collation->name, strlen(collation->name), scs);
+ else
+ table->field[COLUMN_COLLATION]-> store(STRING_WITH_LEN(unknown), scs);
+
+ tz= flags.time_zone->get_name();
+ if (likely(tz))
+ table->field[COLUMN_TIMEZONE]->store(tz->ptr(), tz->length(), scs);
+ else
+ table->field[COLUMN_TIMEZONE]-> store(STRING_WITH_LEN(unknown), scs);
+ table->field[COLUMN_DEFAULT_WEEK_FORMAT]->store(flags.default_week_format, 0);
+ table->field[COLUMN_DIV_PRECISION_INCREMENT]->store(flags.div_precision_increment, 0);
+
+ sql_mode_string_representation(thd, flags.sql_mode, &sql_mode_str);
+ table->field[COLUMN_SQL_MODE]->store(sql_mode_str.str, sql_mode_str.length, scs);
+
+ table->field[COLUMN_LC_TIME_NAMES]->store(flags.lc_time_names->name,strlen(flags.lc_time_names->name), scs);
+
+ table->field[COLUMN_CLIENT_LONG_FLAG]->store(flags.client_long_flag, 0);
+ table->field[COLUMN_CLIENT_PROTOCOL_41]->store(flags.client_protocol_41, 0);
+ table->field[COLUMN_PROTOCOL_TYPE]->store(flags.protocol_type, 0);
+ table->field[COLUMN_MORE_RESULTS_EXISTS]->store(flags.more_results_exists, 0);
+ table->field[COLUMN_IN_TRANS]->store(flags.in_trans, 0);
+ table->field[COLUMN_AUTOCOMMIT]->store(flags.autocommit, 0);
+ table->field[COLUMN_PKT_NR]->store(flags.pkt_nr, 0);
+ table->field[COLUMN_HITS]->store(query_cache_query->hits(), 0);
+
+ /* The database against which the statement is executed is part of the
+ query cache query key
+ */
+ compile_time_assert(QUERY_CACHE_DB_LENGTH_SIZE == 2);
+ db= key + statement_text_length + 1 + QUERY_CACHE_DB_LENGTH_SIZE;
+ db_length= uint2korr(db - QUERY_CACHE_DB_LENGTH_SIZE);
+
+ table->field[COLUMN_STATEMENT_SCHEMA]->store(db, db_length, scs);
+
+ /* If we have result blocks, process them */
+ first_result_block= query_cache_query->result();
+ if(query_cache_query->is_results_ready() &&
+ first_result_block)
+ {
+ /* initialize so we can loop over the result blocks*/
+ result_block= first_result_block;
+ result_blocks_count = 1;
+ result_blocks_size = result_block->length;
+ result_blocks_size_used = result_block->used;
+
+ /* loop over the result blocks*/
+ while((result_block= result_block->next)!=first_result_block)
+ {
+ /* calculate total number of result blocks */
+ result_blocks_count++;
+ /* calculate total size of result blocks */
+ result_blocks_size += result_block->length;
+ /* calculate total of used size of result blocks */
+ result_blocks_size_used += result_block->used;
+ }
+ }
+ else
+ {
+ result_blocks_count = 0;
+ result_blocks_size = 0;
+ result_blocks_size_used = 0;
+ }
+ table->field[COLUMN_RESULT_BLOCKS_COUNT]->store(result_blocks_count, 0);
+ table->field[COLUMN_RESULT_BLOCKS_SIZE]->store(result_blocks_size, 0);
+ table->field[COLUMN_RESULT_BLOCKS_SIZE_USED]->
+ store(result_blocks_size_used, 0);
+
+ if (schema_table_store_record(thd, table))
+ goto cleanup;
+ }
+ status = 0;
+
+cleanup:
+ qc->unlock();
+ return status;
+}
+
+static int qc_info_plugin_init(void *p)
+{
+ ST_SCHEMA_TABLE *schema= (ST_SCHEMA_TABLE *)p;
+
+ schema->fields_info= Show::qc_info_fields;
+ schema->fill_table= qc_info_fill_table;
+ qc = (Accessible_Query_Cache *)&query_cache;
+
+ return qc == 0;
+}
+
+
+static struct st_mysql_information_schema qc_info_plugin=
+{ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+/*
+ Plugin library descriptor
+*/
+
+maria_declare_plugin(query_cache_info)
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &qc_info_plugin,
+ "QUERY_CACHE_INFO",
+ "Roland Bouman, Daniel Black",
+ "Lists all queries in the query cache.",
+ PLUGIN_LICENSE_BSD,
+ qc_info_plugin_init, /* Plugin Init */
+ 0, /* Plugin Deinit */
+ 0x0101, /* version, hex */
+ NULL, /* status variables */
+ NULL, /* system variables */
+ "1.1", /* version as a string */
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
+
diff --git a/plugin/query_response_time/CMakeLists.txt b/plugin/query_response_time/CMakeLists.txt
new file mode 100644
index 00000000..112d72e4
--- /dev/null
+++ b/plugin/query_response_time/CMakeLists.txt
@@ -0,0 +1,3 @@
+ADD_DEFINITIONS(-DHAVE_RESPONSE_TIME_DISTRIBUTION)
+MYSQL_ADD_PLUGIN(QUERY_RESPONSE_TIME query_response_time.cc plugin.cc
+ RECOMPILE_FOR_EMBEDDED)
diff --git a/plugin/query_response_time/mysql-test/query_response_time/basic.result b/plugin/query_response_time/mysql-test/query_response_time/basic.result
new file mode 100644
index 00000000..d2de1b23
--- /dev/null
+++ b/plugin/query_response_time/mysql-test/query_response_time/basic.result
@@ -0,0 +1,27 @@
+SHOW VARIABLES WHERE VARIABLE_NAME LIKE 'query_response_time%' AND VARIABLE_NAME!='query_response_time_exec_time_debug';
+Variable_name Value
+query_response_time_flush OFF
+query_response_time_range_base 10
+query_response_time_stats OFF
+SHOW CREATE TABLE INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+Table Create Table
+QUERY_RESPONSE_TIME CREATE TEMPORARY TABLE `QUERY_RESPONSE_TIME` (
+ `TIME` varchar(14) NOT NULL DEFAULT '',
+ `COUNT` int(11) unsigned NOT NULL DEFAULT 0,
+ `TOTAL` varchar(14) NOT NULL DEFAULT ''
+) ENGINE=MEMORY DEFAULT CHARSET=utf8
+SELECT PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_TYPE, PLUGIN_AUTHOR, PLUGIN_DESCRIPTION, PLUGIN_LICENSE, PLUGIN_MATURITY FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE 'query_response_time%';;
+PLUGIN_NAME QUERY_RESPONSE_TIME
+PLUGIN_VERSION 1.0
+PLUGIN_TYPE INFORMATION SCHEMA
+PLUGIN_AUTHOR Percona and Sergey Vojtovich
+PLUGIN_DESCRIPTION Query Response Time Distribution INFORMATION_SCHEMA Plugin
+PLUGIN_LICENSE GPL
+PLUGIN_MATURITY Stable
+PLUGIN_NAME QUERY_RESPONSE_TIME_AUDIT
+PLUGIN_VERSION 1.0
+PLUGIN_TYPE AUDIT
+PLUGIN_AUTHOR Percona and Sergey Vojtovich
+PLUGIN_DESCRIPTION Query Response Time Distribution Audit Plugin
+PLUGIN_LICENSE GPL
+PLUGIN_MATURITY Stable
diff --git a/plugin/query_response_time/mysql-test/query_response_time/basic.test b/plugin/query_response_time/mysql-test/query_response_time/basic.test
new file mode 100644
index 00000000..e46c8035
--- /dev/null
+++ b/plugin/query_response_time/mysql-test/query_response_time/basic.test
@@ -0,0 +1,3 @@
+SHOW VARIABLES WHERE VARIABLE_NAME LIKE 'query_response_time%' AND VARIABLE_NAME!='query_response_time_exec_time_debug';
+SHOW CREATE TABLE INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+--query_vertical SELECT PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_TYPE, PLUGIN_AUTHOR, PLUGIN_DESCRIPTION, PLUGIN_LICENSE, PLUGIN_MATURITY FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE 'query_response_time%';
diff --git a/plugin/query_response_time/mysql-test/query_response_time/query_response_time-stored.inc b/plugin/query_response_time/mysql-test/query_response_time/query_response_time-stored.inc
new file mode 100644
index 00000000..e86594d6
--- /dev/null
+++ b/plugin/query_response_time/mysql-test/query_response_time/query_response_time-stored.inc
@@ -0,0 +1,36 @@
+SET SESSION query_response_time_exec_time_debug=100000;
+
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+EVAL SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=$base;
+SET GLOBAL query_response_time_flush=1;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+
+CALL test_f(310000);
+CALL test_f(320000);
+CALL test_f(330000);
+CALL test_f(340000);
+CALL test_f(350000);
+CALL test_f(360000);
+CALL test_f(370000);
+CALL test_f(380000);
+CALL test_f(390000);
+CALL test_f(400000);
+CALL test_f(1100000);
+CALL test_f(1200000);
+CALL test_f(1300000);
+CALL test_f(1500000);
+CALL test_f(1400000);
+CALL test_f(500000);
+CALL test_f(2100000);
+CALL test_f(2300000);
+CALL test_f(2500000);
+CALL test_f(3100000);
+CALL test_f(4100000);
+CALL test_f(5100000);
+
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+
+SET SESSION query_response_time_exec_time_debug=default;
diff --git a/plugin/query_response_time/mysql-test/query_response_time/query_response_time-stored.result b/plugin/query_response_time/mysql-test/query_response_time/query_response_time-stored.result
new file mode 100644
index 00000000..bec7007d
--- /dev/null
+++ b/plugin/query_response_time/mysql-test/query_response_time/query_response_time-stored.result
@@ -0,0 +1,392 @@
+CREATE TABLE t(a INT);
+CREATE PROCEDURE test_f(t INT)
+BEGIN
+SET SESSION query_response_time_exec_time_debug=t;
+INSERT INTO t VALUES(1);
+SET SESSION query_response_time_exec_time_debug=100000;
+DELETE FROM t;
+END^
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=1;
+Warnings:
+Warning 1292 Truncated incorrect query_response_time_range_base value: '1'
+SET GLOBAL query_response_time_flush=1;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+CALL test_f(310000);
+CALL test_f(320000);
+CALL test_f(330000);
+CALL test_f(340000);
+CALL test_f(350000);
+CALL test_f(360000);
+CALL test_f(370000);
+CALL test_f(380000);
+CALL test_f(390000);
+CALL test_f(400000);
+CALL test_f(1100000);
+CALL test_f(1200000);
+CALL test_f(1300000);
+CALL test_f(1500000);
+CALL test_f(1400000);
+CALL test_f(500000);
+CALL test_f(2100000);
+CALL test_f(2300000);
+CALL test_f(2500000);
+CALL test_f(3100000);
+CALL test_f(4100000);
+CALL test_f(5100000);
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 2
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000001 45 0.000000
+ 0.000003 0 0.000000
+ 0.000007 0 0.000000
+ 0.000015 0 0.000000
+ 0.000030 0 0.000000
+ 0.000061 0 0.000000
+ 0.000122 0 0.000000
+ 0.000244 0 0.000000
+ 0.000488 0 0.000000
+ 0.000976 0 0.000000
+ 0.001953 0 0.000000
+ 0.003906 0 0.000000
+ 0.007812 0 0.000000
+ 0.015625 0 0.000000
+ 0.031250 0 0.000000
+ 0.062500 0 0.000000
+ 0.125000 44 4.400000
+ 0.250000 0 0.000000
+ 0.500000 10 3.550000
+ 1.000000 1 0.500000
+ 2.000000 5 6.500000
+ 4.000000 4 10.000000
+ 8.000000 2 9.200000
+ 16.000000 0 0.000000
+ 32.000000 0 0.000000
+ 64.000000 0 0.000000
+ 128.000000 0 0.000000
+ 256.000000 0 0.000000
+ 512.000000 0 0.000000
+ 1024.000000 0 0.000000
+ 2048.000000 0 0.000000
+ 4096.000000 0 0.000000
+ 8192.000000 0 0.000000
+ 16384.000000 0 0.000000
+ 32768.000000 0 0.000000
+ 65536.000000 0 0.000000
+ 131072.000000 0 0.000000
+ 262144.000000 0 0.000000
+ 524288.000000 0 0.000000
+1048576.000000 0 0.000000
+2097152.000000 0 0.000000
+4194304.000000 0 0.000000
+8388608.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=2;
+SET GLOBAL query_response_time_flush=1;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+CALL test_f(310000);
+CALL test_f(320000);
+CALL test_f(330000);
+CALL test_f(340000);
+CALL test_f(350000);
+CALL test_f(360000);
+CALL test_f(370000);
+CALL test_f(380000);
+CALL test_f(390000);
+CALL test_f(400000);
+CALL test_f(1100000);
+CALL test_f(1200000);
+CALL test_f(1300000);
+CALL test_f(1500000);
+CALL test_f(1400000);
+CALL test_f(500000);
+CALL test_f(2100000);
+CALL test_f(2300000);
+CALL test_f(2500000);
+CALL test_f(3100000);
+CALL test_f(4100000);
+CALL test_f(5100000);
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 2
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000001 45 0.000000
+ 0.000003 0 0.000000
+ 0.000007 0 0.000000
+ 0.000015 0 0.000000
+ 0.000030 0 0.000000
+ 0.000061 0 0.000000
+ 0.000122 0 0.000000
+ 0.000244 0 0.000000
+ 0.000488 0 0.000000
+ 0.000976 0 0.000000
+ 0.001953 0 0.000000
+ 0.003906 0 0.000000
+ 0.007812 0 0.000000
+ 0.015625 0 0.000000
+ 0.031250 0 0.000000
+ 0.062500 0 0.000000
+ 0.125000 44 4.400000
+ 0.250000 0 0.000000
+ 0.500000 10 3.550000
+ 1.000000 1 0.500000
+ 2.000000 5 6.500000
+ 4.000000 4 10.000000
+ 8.000000 2 9.200000
+ 16.000000 0 0.000000
+ 32.000000 0 0.000000
+ 64.000000 0 0.000000
+ 128.000000 0 0.000000
+ 256.000000 0 0.000000
+ 512.000000 0 0.000000
+ 1024.000000 0 0.000000
+ 2048.000000 0 0.000000
+ 4096.000000 0 0.000000
+ 8192.000000 0 0.000000
+ 16384.000000 0 0.000000
+ 32768.000000 0 0.000000
+ 65536.000000 0 0.000000
+ 131072.000000 0 0.000000
+ 262144.000000 0 0.000000
+ 524288.000000 0 0.000000
+1048576.000000 0 0.000000
+2097152.000000 0 0.000000
+4194304.000000 0 0.000000
+8388608.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=10;
+SET GLOBAL query_response_time_flush=1;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+CALL test_f(310000);
+CALL test_f(320000);
+CALL test_f(330000);
+CALL test_f(340000);
+CALL test_f(350000);
+CALL test_f(360000);
+CALL test_f(370000);
+CALL test_f(380000);
+CALL test_f(390000);
+CALL test_f(400000);
+CALL test_f(1100000);
+CALL test_f(1200000);
+CALL test_f(1300000);
+CALL test_f(1500000);
+CALL test_f(1400000);
+CALL test_f(500000);
+CALL test_f(2100000);
+CALL test_f(2300000);
+CALL test_f(2500000);
+CALL test_f(3100000);
+CALL test_f(4100000);
+CALL test_f(5100000);
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 10
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000001 45 0.000000
+ 0.000010 0 0.000000
+ 0.000100 0 0.000000
+ 0.001000 0 0.000000
+ 0.010000 0 0.000000
+ 0.100000 0 0.000000
+ 1.000000 55 8.450000
+ 10.000000 11 25.700000
+ 100.000000 0 0.000000
+ 1000.000000 0 0.000000
+ 10000.000000 0 0.000000
+ 100000.000000 0 0.000000
+1000000.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=7;
+SET GLOBAL query_response_time_flush=1;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+CALL test_f(310000);
+CALL test_f(320000);
+CALL test_f(330000);
+CALL test_f(340000);
+CALL test_f(350000);
+CALL test_f(360000);
+CALL test_f(370000);
+CALL test_f(380000);
+CALL test_f(390000);
+CALL test_f(400000);
+CALL test_f(1100000);
+CALL test_f(1200000);
+CALL test_f(1300000);
+CALL test_f(1500000);
+CALL test_f(1400000);
+CALL test_f(500000);
+CALL test_f(2100000);
+CALL test_f(2300000);
+CALL test_f(2500000);
+CALL test_f(3100000);
+CALL test_f(4100000);
+CALL test_f(5100000);
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 7
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000001 45 0.000000
+ 0.000008 0 0.000000
+ 0.000059 0 0.000000
+ 0.000416 0 0.000000
+ 0.002915 0 0.000000
+ 0.020408 0 0.000000
+ 0.142857 44 4.400000
+ 1.000000 11 4.050000
+ 7.000000 11 25.700000
+ 49.000000 0 0.000000
+ 343.000000 0 0.000000
+ 2401.000000 0 0.000000
+ 16807.000000 0 0.000000
+ 117649.000000 0 0.000000
+ 823543.000000 0 0.000000
+5764801.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=156;
+SET GLOBAL query_response_time_flush=1;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+CALL test_f(310000);
+CALL test_f(320000);
+CALL test_f(330000);
+CALL test_f(340000);
+CALL test_f(350000);
+CALL test_f(360000);
+CALL test_f(370000);
+CALL test_f(380000);
+CALL test_f(390000);
+CALL test_f(400000);
+CALL test_f(1100000);
+CALL test_f(1200000);
+CALL test_f(1300000);
+CALL test_f(1500000);
+CALL test_f(1400000);
+CALL test_f(500000);
+CALL test_f(2100000);
+CALL test_f(2300000);
+CALL test_f(2500000);
+CALL test_f(3100000);
+CALL test_f(4100000);
+CALL test_f(5100000);
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 156
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000041 45 0.000000
+ 0.006410 0 0.000000
+ 1.000000 55 8.450000
+ 156.000000 11 25.700000
+ 24336.000000 0 0.000000
+3796416.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=1000;
+SET GLOBAL query_response_time_flush=1;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+CALL test_f(310000);
+CALL test_f(320000);
+CALL test_f(330000);
+CALL test_f(340000);
+CALL test_f(350000);
+CALL test_f(360000);
+CALL test_f(370000);
+CALL test_f(380000);
+CALL test_f(390000);
+CALL test_f(400000);
+CALL test_f(1100000);
+CALL test_f(1200000);
+CALL test_f(1300000);
+CALL test_f(1500000);
+CALL test_f(1400000);
+CALL test_f(500000);
+CALL test_f(2100000);
+CALL test_f(2300000);
+CALL test_f(2500000);
+CALL test_f(3100000);
+CALL test_f(4100000);
+CALL test_f(5100000);
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 1000
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000001 45 0.000000
+ 0.001000 0 0.000000
+ 1.000000 55 8.450000
+ 1000.000000 11 25.700000
+1000000.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=1001;
+Warnings:
+Warning 1292 Truncated incorrect query_response_time_range_base value: '1001'
+SET GLOBAL query_response_time_flush=1;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+CALL test_f(310000);
+CALL test_f(320000);
+CALL test_f(330000);
+CALL test_f(340000);
+CALL test_f(350000);
+CALL test_f(360000);
+CALL test_f(370000);
+CALL test_f(380000);
+CALL test_f(390000);
+CALL test_f(400000);
+CALL test_f(1100000);
+CALL test_f(1200000);
+CALL test_f(1300000);
+CALL test_f(1500000);
+CALL test_f(1400000);
+CALL test_f(500000);
+CALL test_f(2100000);
+CALL test_f(2300000);
+CALL test_f(2500000);
+CALL test_f(3100000);
+CALL test_f(4100000);
+CALL test_f(5100000);
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 1000
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000001 45 0.000000
+ 0.001000 0 0.000000
+ 1.000000 55 8.450000
+ 1000.000000 11 25.700000
+1000000.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=default;
+DROP PROCEDURE test_f;
+DROP TABLE t;
diff --git a/plugin/query_response_time/mysql-test/query_response_time/query_response_time-stored.test b/plugin/query_response_time/mysql-test/query_response_time/query_response_time-stored.test
new file mode 100644
index 00000000..e281bd35
--- /dev/null
+++ b/plugin/query_response_time/mysql-test/query_response_time/query_response_time-stored.test
@@ -0,0 +1,44 @@
+--source include/have_debug.inc
+
+# The file with expected results fits only to a run without
+# ps-protocol/sp-protocol/cursor-protocol/view-protocol.
+if (`SELECT $PS_PROTOCOL + $SP_PROTOCOL + $CURSOR_PROTOCOL
+ + $VIEW_PROTOCOL > 0`)
+{
+ --skip Test requires: ps-protocol/sp-protocol/cursor-protocol/view-protocol disabled
+}
+
+
+CREATE TABLE t(a INT);
+
+delimiter ^;
+CREATE PROCEDURE test_f(t INT)
+BEGIN
+ SET SESSION query_response_time_exec_time_debug=t;
+ INSERT INTO t VALUES(1);
+ SET SESSION query_response_time_exec_time_debug=100000;
+ DELETE FROM t;
+END^
+delimiter ;^
+
+--let base=1
+--source query_response_time-stored.inc
+--let base=2
+--source query_response_time-stored.inc
+--let base=10
+--source query_response_time-stored.inc
+--let base=7
+--source query_response_time-stored.inc
+--let base=156
+--source query_response_time-stored.inc
+--let base=1000
+--source query_response_time-stored.inc
+--let base=1001
+--source query_response_time-stored.inc
+
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=default;
+
+DROP PROCEDURE test_f;
+
+DROP TABLE t;
diff --git a/plugin/query_response_time/mysql-test/query_response_time/query_response_time.inc b/plugin/query_response_time/mysql-test/query_response_time/query_response_time.inc
new file mode 100644
index 00000000..d13215aa
--- /dev/null
+++ b/plugin/query_response_time/mysql-test/query_response_time/query_response_time.inc
@@ -0,0 +1,41 @@
+SET SESSION query_response_time_exec_time_debug=100000;
+
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+EVAL SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=$base;
+FLUSH QUERY_RESPONSE_TIME;
+# Following two queries check works of FLUSH and
+# respecting of "QUERY_RESPONSE_TIME_STATS" variable (see launchpad bug #855312)
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+
+SET SESSION query_response_time_exec_time_debug=310000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=320000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=330000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=340000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=350000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=360000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=370000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=380000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=390000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=400000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=1100000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=1200000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=1300000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=1500000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=1400000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=500000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=2100000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=2300000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=2500000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=3100000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=4100000; SELECT 1;
+SET SESSION query_response_time_exec_time_debug=5100000; SELECT 1;
+
+SET SESSION query_response_time_exec_time_debug=100000;
+
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+SHOW QUERY_RESPONSE_TIME;
+
+SET SESSION query_response_time_exec_time_debug=default;
diff --git a/plugin/query_response_time/mysql-test/query_response_time/query_response_time.result b/plugin/query_response_time/mysql-test/query_response_time/query_response_time.result
new file mode 100644
index 00000000..14822c35
--- /dev/null
+++ b/plugin/query_response_time/mysql-test/query_response_time/query_response_time.result
@@ -0,0 +1,1003 @@
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=1;
+Warnings:
+Warning 1292 Truncated incorrect query_response_time_range_base value: '1'
+FLUSH QUERY_RESPONSE_TIME;
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000001 0 0.000000
+ 0.000003 0 0.000000
+ 0.000007 0 0.000000
+ 0.000015 0 0.000000
+ 0.000030 0 0.000000
+ 0.000061 0 0.000000
+ 0.000122 0 0.000000
+ 0.000244 0 0.000000
+ 0.000488 0 0.000000
+ 0.000976 0 0.000000
+ 0.001953 0 0.000000
+ 0.003906 0 0.000000
+ 0.007812 0 0.000000
+ 0.015625 0 0.000000
+ 0.031250 0 0.000000
+ 0.062500 0 0.000000
+ 0.125000 0 0.000000
+ 0.250000 0 0.000000
+ 0.500000 0 0.000000
+ 1.000000 0 0.000000
+ 2.000000 0 0.000000
+ 4.000000 0 0.000000
+ 8.000000 0 0.000000
+ 16.000000 0 0.000000
+ 32.000000 0 0.000000
+ 64.000000 0 0.000000
+ 128.000000 0 0.000000
+ 256.000000 0 0.000000
+ 512.000000 0 0.000000
+ 1024.000000 0 0.000000
+ 2048.000000 0 0.000000
+ 4096.000000 0 0.000000
+ 8192.000000 0 0.000000
+ 16384.000000 0 0.000000
+ 32768.000000 0 0.000000
+ 65536.000000 0 0.000000
+ 131072.000000 0 0.000000
+ 262144.000000 0 0.000000
+ 524288.000000 0 0.000000
+1048576.000000 0 0.000000
+2097152.000000 0 0.000000
+4194304.000000 0 0.000000
+8388608.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+SET SESSION query_response_time_exec_time_debug=310000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=320000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=330000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=340000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=350000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=360000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=370000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=380000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=390000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1200000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=3100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=4100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=5100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 2
+SHOW QUERY_RESPONSE_TIME;
+Time Count Total
+ 0.000001 24 0.000000
+ 0.000003 0 0.000000
+ 0.000007 0 0.000000
+ 0.000015 0 0.000000
+ 0.000030 0 0.000000
+ 0.000061 0 0.000000
+ 0.000122 0 0.000000
+ 0.000244 0 0.000000
+ 0.000488 0 0.000000
+ 0.000976 0 0.000000
+ 0.001953 0 0.000000
+ 0.003906 0 0.000000
+ 0.007812 0 0.000000
+ 0.015625 0 0.000000
+ 0.031250 0 0.000000
+ 0.062500 0 0.000000
+ 0.125000 0 0.000000
+ 0.250000 0 0.000000
+ 0.500000 10 3.550000
+ 1.000000 1 0.500000
+ 2.000000 5 6.500000
+ 4.000000 4 10.000000
+ 8.000000 2 9.200000
+ 16.000000 0 0.000000
+ 32.000000 0 0.000000
+ 64.000000 0 0.000000
+ 128.000000 0 0.000000
+ 256.000000 0 0.000000
+ 512.000000 0 0.000000
+ 1024.000000 0 0.000000
+ 2048.000000 0 0.000000
+ 4096.000000 0 0.000000
+ 8192.000000 0 0.000000
+ 16384.000000 0 0.000000
+ 32768.000000 0 0.000000
+ 65536.000000 0 0.000000
+ 131072.000000 0 0.000000
+ 262144.000000 0 0.000000
+ 524288.000000 0 0.000000
+1048576.000000 0 0.000000
+2097152.000000 0 0.000000
+4194304.000000 0 0.000000
+8388608.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=2;
+FLUSH QUERY_RESPONSE_TIME;
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000001 0 0.000000
+ 0.000003 0 0.000000
+ 0.000007 0 0.000000
+ 0.000015 0 0.000000
+ 0.000030 0 0.000000
+ 0.000061 0 0.000000
+ 0.000122 0 0.000000
+ 0.000244 0 0.000000
+ 0.000488 0 0.000000
+ 0.000976 0 0.000000
+ 0.001953 0 0.000000
+ 0.003906 0 0.000000
+ 0.007812 0 0.000000
+ 0.015625 0 0.000000
+ 0.031250 0 0.000000
+ 0.062500 0 0.000000
+ 0.125000 0 0.000000
+ 0.250000 0 0.000000
+ 0.500000 0 0.000000
+ 1.000000 0 0.000000
+ 2.000000 0 0.000000
+ 4.000000 0 0.000000
+ 8.000000 0 0.000000
+ 16.000000 0 0.000000
+ 32.000000 0 0.000000
+ 64.000000 0 0.000000
+ 128.000000 0 0.000000
+ 256.000000 0 0.000000
+ 512.000000 0 0.000000
+ 1024.000000 0 0.000000
+ 2048.000000 0 0.000000
+ 4096.000000 0 0.000000
+ 8192.000000 0 0.000000
+ 16384.000000 0 0.000000
+ 32768.000000 0 0.000000
+ 65536.000000 0 0.000000
+ 131072.000000 0 0.000000
+ 262144.000000 0 0.000000
+ 524288.000000 0 0.000000
+1048576.000000 0 0.000000
+2097152.000000 0 0.000000
+4194304.000000 0 0.000000
+8388608.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+SET SESSION query_response_time_exec_time_debug=310000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=320000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=330000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=340000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=350000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=360000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=370000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=380000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=390000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1200000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=3100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=4100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=5100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 2
+SHOW QUERY_RESPONSE_TIME;
+Time Count Total
+ 0.000001 24 0.000000
+ 0.000003 0 0.000000
+ 0.000007 0 0.000000
+ 0.000015 0 0.000000
+ 0.000030 0 0.000000
+ 0.000061 0 0.000000
+ 0.000122 0 0.000000
+ 0.000244 0 0.000000
+ 0.000488 0 0.000000
+ 0.000976 0 0.000000
+ 0.001953 0 0.000000
+ 0.003906 0 0.000000
+ 0.007812 0 0.000000
+ 0.015625 0 0.000000
+ 0.031250 0 0.000000
+ 0.062500 0 0.000000
+ 0.125000 0 0.000000
+ 0.250000 0 0.000000
+ 0.500000 10 3.550000
+ 1.000000 1 0.500000
+ 2.000000 5 6.500000
+ 4.000000 4 10.000000
+ 8.000000 2 9.200000
+ 16.000000 0 0.000000
+ 32.000000 0 0.000000
+ 64.000000 0 0.000000
+ 128.000000 0 0.000000
+ 256.000000 0 0.000000
+ 512.000000 0 0.000000
+ 1024.000000 0 0.000000
+ 2048.000000 0 0.000000
+ 4096.000000 0 0.000000
+ 8192.000000 0 0.000000
+ 16384.000000 0 0.000000
+ 32768.000000 0 0.000000
+ 65536.000000 0 0.000000
+ 131072.000000 0 0.000000
+ 262144.000000 0 0.000000
+ 524288.000000 0 0.000000
+1048576.000000 0 0.000000
+2097152.000000 0 0.000000
+4194304.000000 0 0.000000
+8388608.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=10;
+FLUSH QUERY_RESPONSE_TIME;
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000001 0 0.000000
+ 0.000010 0 0.000000
+ 0.000100 0 0.000000
+ 0.001000 0 0.000000
+ 0.010000 0 0.000000
+ 0.100000 0 0.000000
+ 1.000000 0 0.000000
+ 10.000000 0 0.000000
+ 100.000000 0 0.000000
+ 1000.000000 0 0.000000
+ 10000.000000 0 0.000000
+ 100000.000000 0 0.000000
+1000000.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+SET SESSION query_response_time_exec_time_debug=310000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=320000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=330000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=340000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=350000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=360000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=370000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=380000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=390000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1200000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=3100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=4100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=5100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 10
+SHOW QUERY_RESPONSE_TIME;
+Time Count Total
+ 0.000001 24 0.000000
+ 0.000010 0 0.000000
+ 0.000100 0 0.000000
+ 0.001000 0 0.000000
+ 0.010000 0 0.000000
+ 0.100000 0 0.000000
+ 1.000000 11 4.050000
+ 10.000000 11 25.700000
+ 100.000000 0 0.000000
+ 1000.000000 0 0.000000
+ 10000.000000 0 0.000000
+ 100000.000000 0 0.000000
+1000000.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=7;
+FLUSH QUERY_RESPONSE_TIME;
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000001 0 0.000000
+ 0.000008 0 0.000000
+ 0.000059 0 0.000000
+ 0.000416 0 0.000000
+ 0.002915 0 0.000000
+ 0.020408 0 0.000000
+ 0.142857 0 0.000000
+ 1.000000 0 0.000000
+ 7.000000 0 0.000000
+ 49.000000 0 0.000000
+ 343.000000 0 0.000000
+ 2401.000000 0 0.000000
+ 16807.000000 0 0.000000
+ 117649.000000 0 0.000000
+ 823543.000000 0 0.000000
+5764801.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+SET SESSION query_response_time_exec_time_debug=310000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=320000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=330000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=340000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=350000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=360000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=370000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=380000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=390000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1200000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=3100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=4100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=5100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 7
+SHOW QUERY_RESPONSE_TIME;
+Time Count Total
+ 0.000001 24 0.000000
+ 0.000008 0 0.000000
+ 0.000059 0 0.000000
+ 0.000416 0 0.000000
+ 0.002915 0 0.000000
+ 0.020408 0 0.000000
+ 0.142857 0 0.000000
+ 1.000000 11 4.050000
+ 7.000000 11 25.700000
+ 49.000000 0 0.000000
+ 343.000000 0 0.000000
+ 2401.000000 0 0.000000
+ 16807.000000 0 0.000000
+ 117649.000000 0 0.000000
+ 823543.000000 0 0.000000
+5764801.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=156;
+FLUSH QUERY_RESPONSE_TIME;
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000041 0 0.000000
+ 0.006410 0 0.000000
+ 1.000000 0 0.000000
+ 156.000000 0 0.000000
+ 24336.000000 0 0.000000
+3796416.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+SET SESSION query_response_time_exec_time_debug=310000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=320000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=330000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=340000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=350000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=360000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=370000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=380000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=390000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1200000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=3100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=4100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=5100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 156
+SHOW QUERY_RESPONSE_TIME;
+Time Count Total
+ 0.000041 24 0.000000
+ 0.006410 0 0.000000
+ 1.000000 11 4.050000
+ 156.000000 11 25.700000
+ 24336.000000 0 0.000000
+3796416.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=1000;
+FLUSH QUERY_RESPONSE_TIME;
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000001 0 0.000000
+ 0.001000 0 0.000000
+ 1.000000 0 0.000000
+ 1000.000000 0 0.000000
+1000000.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+SET SESSION query_response_time_exec_time_debug=310000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=320000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=330000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=340000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=350000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=360000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=370000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=380000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=390000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1200000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=3100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=4100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=5100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 1000
+SHOW QUERY_RESPONSE_TIME;
+Time Count Total
+ 0.000001 24 0.000000
+ 0.001000 0 0.000000
+ 1.000000 11 4.050000
+ 1000.000000 11 25.700000
+1000000.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=1001;
+Warnings:
+Warning 1292 Truncated incorrect query_response_time_range_base value: '1001'
+FLUSH QUERY_RESPONSE_TIME;
+SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME;
+TIME COUNT TOTAL
+ 0.000001 0 0.000000
+ 0.001000 0 0.000000
+ 1.000000 0 0.000000
+ 1000.000000 0 0.000000
+1000000.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=1;
+SET SESSION query_response_time_exec_time_debug=310000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=320000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=330000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=340000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=350000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=360000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=370000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=380000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=390000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1200000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=1400000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2300000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=2500000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=3100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=4100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=5100000;
+SELECT 1;
+1
+1
+SET SESSION query_response_time_exec_time_debug=100000;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=0;
+SHOW GLOBAL VARIABLES where Variable_name like 'QUERY_RESPONSE_TIME_RANGE_BASE';
+Variable_name Value
+query_response_time_range_base 1000
+SHOW QUERY_RESPONSE_TIME;
+Time Count Total
+ 0.000001 24 0.000000
+ 0.001000 0 0.000000
+ 1.000000 11 4.050000
+ 1000.000000 11 25.700000
+1000000.000000 0 0.000000
+TOO LONG 0 TOO LONG
+SET SESSION query_response_time_exec_time_debug=default;
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=default;
diff --git a/plugin/query_response_time/mysql-test/query_response_time/query_response_time.test b/plugin/query_response_time/mysql-test/query_response_time/query_response_time.test
new file mode 100644
index 00000000..5caec36f
--- /dev/null
+++ b/plugin/query_response_time/mysql-test/query_response_time/query_response_time.test
@@ -0,0 +1,28 @@
+--source include/have_debug.inc
+
+# The file with expected results fits only to a run without
+# ps-protocol/sp-protocol/cursor-protocol/view-protocol.
+if (`SELECT $PS_PROTOCOL + $SP_PROTOCOL + $CURSOR_PROTOCOL
+ + $VIEW_PROTOCOL > 0`)
+{
+ --skip Test requires: ps-protocol/sp-protocol/cursor-protocol/view-protocol disabled
+}
+
+
+--let base=1
+--source query_response_time.inc
+--let base=2
+--source query_response_time.inc
+--let base=10
+--source query_response_time.inc
+--let base=7
+--source query_response_time.inc
+--let base=156
+--source query_response_time.inc
+--let base=1000
+--source query_response_time.inc
+--let base=1001
+--source query_response_time.inc
+
+SET GLOBAL QUERY_RESPONSE_TIME_RANGE_BASE=default;
+SET GLOBAL QUERY_RESPONSE_TIME_STATS=default;
diff --git a/plugin/query_response_time/mysql-test/query_response_time/suite.opt b/plugin/query_response_time/mysql-test/query_response_time/suite.opt
new file mode 100644
index 00000000..7283ce84
--- /dev/null
+++ b/plugin/query_response_time/mysql-test/query_response_time/suite.opt
@@ -0,0 +1 @@
+--plugin-load-add=$QUERY_RESPONSE_TIME_SO --plugin-query-response-time=ON --plugin-query-response-time-audit=ON
diff --git a/plugin/query_response_time/mysql-test/query_response_time/suite.pm b/plugin/query_response_time/mysql-test/query_response_time/suite.pm
new file mode 100644
index 00000000..5b4983bc
--- /dev/null
+++ b/plugin/query_response_time/mysql-test/query_response_time/suite.pm
@@ -0,0 +1,14 @@
+package My::Suite::Query_response_time;
+
+@ISA = qw(My::Suite);
+
+return "No QUERY_RESPONSE_TIME plugin" unless
+ $ENV{QUERY_RESPONSE_TIME_SO} or
+ $::mysqld_variables{'query-response-time'} eq "ON";
+
+return "Not run for embedded server" if $::opt_embedded_server;
+
+sub is_default { 1 }
+
+bless { };
+
diff --git a/plugin/query_response_time/plugin.cc b/plugin/query_response_time/plugin.cc
new file mode 100644
index 00000000..0362c6e2
--- /dev/null
+++ b/plugin/query_response_time/plugin.cc
@@ -0,0 +1,168 @@
+/* Copyright (C) 2013 Percona and Sergey Vojtovich
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#define MYSQL_SERVER
+#include <my_global.h>
+#include <sql_class.h>
+#include <sql_i_s.h>
+#include <sql_show.h>
+#include <mysql/plugin_audit.h>
+#include "query_response_time.h"
+
+
+ulong opt_query_response_time_range_base= QRT_DEFAULT_BASE;
+my_bool opt_query_response_time_stats= 0;
+static my_bool opt_query_response_time_flush= 0;
+
+
+static void query_response_time_flush_update(
+ MYSQL_THD thd __attribute__((unused)),
+ struct st_mysql_sys_var *var __attribute__((unused)),
+ void *tgt __attribute__((unused)),
+ const void *save __attribute__((unused)))
+{
+ query_response_time_flush();
+}
+
+
+static MYSQL_SYSVAR_ULONG(range_base, opt_query_response_time_range_base,
+ PLUGIN_VAR_RQCMDARG,
+ "Select base of log for query_response_time ranges. WARNING: variable "
+ "change affect only after flush",
+ NULL, NULL, QRT_DEFAULT_BASE, 2, QRT_MAXIMUM_BASE, 1);
+static MYSQL_SYSVAR_BOOL(stats, opt_query_response_time_stats,
+ PLUGIN_VAR_OPCMDARG,
+ "Enable or disable query response time statisics collecting",
+ NULL, NULL, FALSE);
+static MYSQL_SYSVAR_BOOL(flush, opt_query_response_time_flush,
+ PLUGIN_VAR_NOCMDOPT,
+ "Update of this variable flushes statistics and re-reads "
+ "query_response_time_range_base",
+ NULL, query_response_time_flush_update, FALSE);
+#ifndef DBUG_OFF
+static MYSQL_THDVAR_ULONGLONG(exec_time_debug, PLUGIN_VAR_NOCMDOPT,
+ "Pretend queries take this many microseconds. When 0 (the default) use "
+ "the actual execution time. Used only for debugging.",
+ NULL, NULL, 0, 0, LONG_TIMEOUT, 1);
+#endif
+
+
+static struct st_mysql_sys_var *query_response_time_info_vars[]=
+{
+ MYSQL_SYSVAR(range_base),
+ MYSQL_SYSVAR(stats),
+ MYSQL_SYSVAR(flush),
+#ifndef DBUG_OFF
+ MYSQL_SYSVAR(exec_time_debug),
+#endif
+ NULL
+};
+
+
+namespace Show {
+
+ST_FIELD_INFO query_response_time_fields_info[] =
+{
+ Column("TIME", Varchar(QRT_TIME_STRING_LENGTH), NOT_NULL, "Time"),
+ Column("COUNT", ULong(), NOT_NULL, "Count"),
+ Column("TOTAL", Varchar(QRT_TIME_STRING_LENGTH), NOT_NULL, "Total"),
+ CEnd()
+};
+
+} // namespace Show
+
+static int query_response_time_info_init(void *p)
+{
+ ST_SCHEMA_TABLE *i_s_query_response_time= (ST_SCHEMA_TABLE *) p;
+ i_s_query_response_time->fields_info= Show::query_response_time_fields_info;
+ i_s_query_response_time->fill_table= query_response_time_fill;
+ i_s_query_response_time->reset_table= query_response_time_flush;
+ query_response_time_init();
+ return 0;
+}
+
+
+static int query_response_time_info_deinit(void *arg __attribute__((unused)))
+{
+ opt_query_response_time_stats= 0;
+ query_response_time_free();
+ return 0;
+}
+
+
+static struct st_mysql_information_schema query_response_time_info_descriptor=
+{ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+
+static void query_response_time_audit_notify(MYSQL_THD thd,
+ unsigned int event_class,
+ const void *event)
+{
+ const struct mysql_event_general *event_general=
+ (const struct mysql_event_general *) event;
+ DBUG_ASSERT(event_class == MYSQL_AUDIT_GENERAL_CLASS);
+ if (event_general->event_subclass == MYSQL_AUDIT_GENERAL_STATUS &&
+ opt_query_response_time_stats)
+ {
+#ifndef DBUG_OFF
+ if (THDVAR(thd, exec_time_debug))
+ query_response_time_collect(thd->lex->sql_command != SQLCOM_SET_OPTION ?
+ THDVAR(thd, exec_time_debug) : 0);
+ else
+#endif
+ query_response_time_collect(thd->utime_after_query - thd->utime_after_lock);
+ }
+}
+
+
+static struct st_mysql_audit query_response_time_audit_descriptor=
+{
+ MYSQL_AUDIT_INTERFACE_VERSION, NULL, query_response_time_audit_notify,
+ { (unsigned long) MYSQL_AUDIT_GENERAL_CLASSMASK }
+};
+
+
+maria_declare_plugin(query_response_time)
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &query_response_time_info_descriptor,
+ "QUERY_RESPONSE_TIME",
+ "Percona and Sergey Vojtovich",
+ "Query Response Time Distribution INFORMATION_SCHEMA Plugin",
+ PLUGIN_LICENSE_GPL,
+ query_response_time_info_init,
+ query_response_time_info_deinit,
+ 0x0100,
+ NULL,
+ query_response_time_info_vars,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+},
+{
+ MYSQL_AUDIT_PLUGIN,
+ &query_response_time_audit_descriptor,
+ "QUERY_RESPONSE_TIME_AUDIT",
+ "Percona and Sergey Vojtovich",
+ "Query Response Time Distribution Audit Plugin",
+ PLUGIN_LICENSE_GPL,
+ NULL,
+ NULL,
+ 0x0100,
+ NULL,
+ NULL,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
diff --git a/plugin/query_response_time/query_response_time.cc b/plugin/query_response_time/query_response_time.cc
new file mode 100644
index 00000000..a669f7d4
--- /dev/null
+++ b/plugin/query_response_time/query_response_time.cc
@@ -0,0 +1,278 @@
+#include "mysql_version.h"
+#include "my_global.h"
+#ifdef HAVE_RESPONSE_TIME_DISTRIBUTION
+#include "mysql_com.h"
+#include "rpl_tblmap.h"
+#include "table.h"
+#include "field.h"
+#include "sql_show.h"
+#include "query_response_time.h"
+
+#define TIME_STRING_POSITIVE_POWER_LENGTH QRT_TIME_STRING_POSITIVE_POWER_LENGTH
+#define TIME_STRING_NEGATIVE_POWER_LENGTH 6
+#define TOTAL_STRING_POSITIVE_POWER_LENGTH QRT_TOTAL_STRING_POSITIVE_POWER_LENGTH
+#define TOTAL_STRING_NEGATIVE_POWER_LENGTH 6
+#define MINIMUM_BASE 2
+#define MAXIMUM_BASE QRT_MAXIMUM_BASE
+#define POSITIVE_POWER_FILLER QRT_POSITIVE_POWER_FILLER
+#define NEGATIVE_POWER_FILLER QRT_NEGATIVE_POWER_FILLER
+#define TIME_OVERFLOW QRT_TIME_OVERFLOW
+#define DEFAULT_BASE QRT_DEFAULT_BASE
+
+#define do_xstr(s) do_str(s)
+#define do_str(s) #s
+#define do_format(filler,width) "%" filler width "lld"
+/*
+ Format strings for snprintf. Generate from:
+ POSITIVE_POWER_FILLER and TIME_STRING_POSITIVE_POWER_LENGTH
+ NEFATIVE_POWER_FILLER and TIME_STRING_NEGATIVE_POWER_LENGTH
+*/
+#define TIME_STRING_POSITIVE_POWER_FORMAT do_format(POSITIVE_POWER_FILLER,do_xstr(TIME_STRING_POSITIVE_POWER_LENGTH))
+#define TIME_STRING_NEGATIVE_POWER_FORMAT do_format(NEGATIVE_POWER_FILLER,do_xstr(TIME_STRING_NEGATIVE_POWER_LENGTH))
+#define TIME_STRING_FORMAT TIME_STRING_POSITIVE_POWER_FORMAT "." TIME_STRING_NEGATIVE_POWER_FORMAT
+
+#define TOTAL_STRING_POSITIVE_POWER_FORMAT do_format(POSITIVE_POWER_FILLER,do_xstr(TOTAL_STRING_POSITIVE_POWER_LENGTH))
+#define TOTAL_STRING_NEGATIVE_POWER_FORMAT do_format(NEGATIVE_POWER_FILLER,do_xstr(TOTAL_STRING_NEGATIVE_POWER_LENGTH))
+#define TOTAL_STRING_FORMAT TOTAL_STRING_POSITIVE_POWER_FORMAT "." TOTAL_STRING_NEGATIVE_POWER_FORMAT
+
+#define TIME_STRING_LENGTH QRT_TIME_STRING_LENGTH
+#define TIME_STRING_BUFFER_LENGTH (TIME_STRING_LENGTH + 1 /* '\0' */)
+
+#define TOTAL_STRING_LENGTH QRT_TOTAL_STRING_LENGTH
+#define TOTAL_STRING_BUFFER_LENGTH (TOTAL_STRING_LENGTH + 1 /* '\0' */)
+
+/*
+ Calculate length of "log linear"
+ 1)
+ (MINIMUM_BASE ^ result) <= (10 ^ STRING_POWER_LENGTH) < (MINIMUM_BASE ^ (result + 1))
+
+ 2)
+ (MINIMUM_BASE ^ result) <= (10 ^ STRING_POWER_LENGTH)
+ and
+ (MINIMUM_BASE ^ (result + 1)) > (10 ^ STRING_POWER_LENGTH)
+
+ 3)
+ result <= LOG(MINIMUM_BASE, 10 ^ STRING_POWER_LENGTH)= STRING_POWER_LENGTH * LOG(MINIMUM_BASE,10)
+ result + 1 > LOG(MINIMUM_BASE, 10 ^ STRING_POWER_LENGTH)= STRING_POWER_LENGTH * LOG(MINIMUM_BASE,10)
+
+ 4) STRING_POWER_LENGTH * LOG(MINIMUM_BASE,10) - 1 < result <= STRING_POWER_LENGTH * LOG(MINIMUM_BASE,10)
+
+ MINIMUM_BASE= 2 always, LOG(MINIMUM_BASE,10)= 3.3219280948873626, result= (int)3.3219280948873626 * STRING_POWER_LENGTH
+
+ Last counter always use for time overflow
+*/
+#define POSITIVE_POWER_COUNT ((int)(3.32192809 * TIME_STRING_POSITIVE_POWER_LENGTH))
+#define NEGATIVE_POWER_COUNT ((int)(3.32192809 * TIME_STRING_NEGATIVE_POWER_LENGTH))
+#define OVERALL_POWER_COUNT (NEGATIVE_POWER_COUNT + 1 + POSITIVE_POWER_COUNT)
+
+#define MILLION ((unsigned long)1000 * 1000)
+
+namespace query_response_time
+{
+
+class utility
+{
+public:
+ utility() : m_base(0)
+ {
+ m_max_dec_value= MILLION;
+ for(int i= 0; TIME_STRING_POSITIVE_POWER_LENGTH > i; ++i)
+ m_max_dec_value *= 10;
+ setup(DEFAULT_BASE);
+ }
+public:
+ uint base() const { return m_base; }
+ uint negative_count() const { return m_negative_count; }
+ uint positive_count() const { return m_positive_count; }
+ uint bound_count() const { return m_bound_count; }
+ ulonglong max_dec_value() const { return m_max_dec_value; }
+ ulonglong bound(uint index) const { return m_bound[ index ]; }
+public:
+ void setup(uint base)
+ {
+ if(base != m_base)
+ {
+ m_base= base;
+
+ const ulonglong million= 1000 * 1000;
+ ulonglong value= million;
+ m_negative_count= 0;
+ while(value > 0)
+ {
+ m_negative_count += 1;
+ value /= m_base;
+ }
+ m_negative_count -= 1;
+
+ value= million;
+ m_positive_count= 0;
+ while(value < m_max_dec_value)
+ {
+ m_positive_count += 1;
+ value *= m_base;
+ }
+ m_bound_count= m_negative_count + m_positive_count;
+
+ value= million;
+ for(uint i= 0; i < m_negative_count; ++i)
+ {
+ value /= m_base;
+ m_bound[m_negative_count - i - 1]= value;
+ }
+ value= million;
+ for(uint i= 0; i < m_positive_count; ++i)
+ {
+ m_bound[m_negative_count + i]= value;
+ value *= m_base;
+ }
+ }
+ }
+private:
+ uint m_base;
+ uint m_negative_count;
+ uint m_positive_count;
+ uint m_bound_count;
+ ulonglong m_max_dec_value; /* for TIME_STRING_POSITIVE_POWER_LENGTH=7 is 10000000 */
+ ulonglong m_bound[OVERALL_POWER_COUNT];
+};
+
+static
+void print_time(char* buffer, std::size_t buffer_size, const char* format,
+ uint64 value)
+{
+ ulonglong second= (value / MILLION);
+ ulonglong microsecond= (value % MILLION);
+ my_snprintf(buffer, buffer_size, format, second, microsecond);
+}
+
+class time_collector
+{
+ utility *m_utility;
+ Atomic_counter<uint32_t> m_count[OVERALL_POWER_COUNT + 1];
+ Atomic_counter<uint64_t> m_total[OVERALL_POWER_COUNT + 1];
+
+public:
+ time_collector(utility& u): m_utility(&u) { flush(); }
+ ~time_collector() { }
+ uint32_t count(uint index) { return m_count[index]; }
+ uint64_t total(uint index) { return m_total[index]; }
+ void flush()
+ {
+ for (auto i= 0; i < OVERALL_POWER_COUNT + 1; i++)
+ {
+ m_count[i]= 0;
+ m_total[i]= 0;
+ }
+ }
+ void collect(uint64_t time)
+ {
+ int i= 0;
+ for(int count= m_utility->bound_count(); count > i; ++i)
+ {
+ if(m_utility->bound(i) > time)
+ {
+ m_count[i]++;
+ m_total[i]+= time;
+ break;
+ }
+ }
+ }
+};
+
+class collector
+{
+public:
+ collector() : m_time(m_utility)
+ {
+ m_utility.setup(DEFAULT_BASE);
+ }
+public:
+ void flush()
+ {
+ m_utility.setup(opt_query_response_time_range_base);
+ m_time.flush();
+ }
+ int fill(THD* thd, TABLE_LIST *tables, COND *cond)
+ {
+ DBUG_ENTER("fill_schema_query_response_time");
+ TABLE *table= static_cast<TABLE*>(tables->table);
+ Field **fields= table->field;
+ for(uint i= 0, count= bound_count() + 1 /* with overflow */; count > i; ++i)
+ {
+ char time[TIME_STRING_BUFFER_LENGTH];
+ char total[TOTAL_STRING_BUFFER_LENGTH];
+ if(i == bound_count())
+ {
+ assert(sizeof(TIME_OVERFLOW) <= TIME_STRING_BUFFER_LENGTH);
+ assert(sizeof(TIME_OVERFLOW) <= TOTAL_STRING_BUFFER_LENGTH);
+ memcpy(time,TIME_OVERFLOW,sizeof(TIME_OVERFLOW));
+ memcpy(total,TIME_OVERFLOW,sizeof(TIME_OVERFLOW));
+ }
+ else
+ {
+ print_time(time, sizeof(time), TIME_STRING_FORMAT, this->bound(i));
+ print_time(total, sizeof(total), TOTAL_STRING_FORMAT, this->total(i));
+ }
+ fields[0]->store(time,strlen(time),system_charset_info);
+ fields[1]->store((longlong)this->count(i),true);
+ fields[2]->store(total,strlen(total),system_charset_info);
+ if (schema_table_store_record(thd, table))
+ {
+ DBUG_RETURN(1);
+ }
+ }
+ DBUG_RETURN(0);
+ }
+ void collect(ulonglong time)
+ {
+ m_time.collect(time);
+ }
+ uint bound_count() const
+ {
+ return m_utility.bound_count();
+ }
+ ulonglong bound(uint index)
+ {
+ return m_utility.bound(index);
+ }
+ ulonglong count(uint index)
+ {
+ return m_time.count(index);
+ }
+ ulonglong total(uint index)
+ {
+ return m_time.total(index);
+ }
+private:
+ utility m_utility;
+ time_collector m_time;
+};
+
+static collector g_collector;
+
+} // namespace query_response_time
+
+void query_response_time_init()
+{
+}
+
+void query_response_time_free()
+{
+ query_response_time::g_collector.flush();
+}
+
+int query_response_time_flush()
+{
+ query_response_time::g_collector.flush();
+ return 0;
+}
+void query_response_time_collect(ulonglong query_time)
+{
+ query_response_time::g_collector.collect(query_time);
+}
+
+int query_response_time_fill(THD* thd, TABLE_LIST *tables, COND *cond)
+{
+ return query_response_time::g_collector.fill(thd,tables,cond);
+}
+#endif // HAVE_RESPONSE_TIME_DISTRIBUTION
diff --git a/plugin/query_response_time/query_response_time.h b/plugin/query_response_time/query_response_time.h
new file mode 100644
index 00000000..f59639f0
--- /dev/null
+++ b/plugin/query_response_time/query_response_time.h
@@ -0,0 +1,67 @@
+#ifndef QUERY_RESPONSE_TIME_H
+#define QUERY_RESPONSE_TIME_H
+
+/*
+ Settings for query response time
+*/
+
+/*
+ Maximum string length for (10 ^ (-1 * QRT_STRING_NEGATIVE_POWER_LENGTH)) in text representation.
+ Example: for 6 is 0.000001
+ Always 2
+
+ Maximum string length for (10 ^ (QRT_STRING_POSITIVE_POWER_LENGTH + 1) - 1) in text representation.
+ Example: for 7 is 9999999.0
+*/
+#define QRT_TIME_STRING_POSITIVE_POWER_LENGTH 7
+#define QRT_TOTAL_STRING_POSITIVE_POWER_LENGTH 7
+
+/*
+ Minimum base for log - ALWAYS 2
+ Maximum base for log:
+*/
+#define QRT_MAXIMUM_BASE 1000
+
+/*
+ Filler for whole number (positive power)
+ Example: for
+ QRT_POSITIVE_POWER_FILLER ' '
+ QRT_POSITIVE_POWER_LENGTH 7
+ and number 7234 result is:
+ ' 7234'
+*/
+#define QRT_POSITIVE_POWER_FILLER ""
+/*
+ Filler for fractional number. Similiary to whole number
+*/
+#define QRT_NEGATIVE_POWER_FILLER "0"
+
+/*
+ Message if time too big for statistic collecting (very long query)
+*/
+#define QRT_TIME_OVERFLOW "TOO LONG"
+
+#define QRT_DEFAULT_BASE 10
+
+#define QRT_TIME_STRING_LENGTH \
+ MY_MAX( (QRT_TIME_STRING_POSITIVE_POWER_LENGTH + 1 /* '.' */ + 6 /*QRT_TIME_STRING_NEGATIVE_POWER_LENGTH*/), \
+ (sizeof(QRT_TIME_OVERFLOW) - 1) )
+
+#define QRT_TOTAL_STRING_LENGTH \
+ MY_MAX( (QRT_TOTAL_STRING_POSITIVE_POWER_LENGTH + 1 /* '.' */ + 6 /*QRT_TOTAL_STRING_NEGATIVE_POWER_LENGTH*/), \
+ (sizeof(QRT_TIME_OVERFLOW) - 1) )
+
+extern ST_SCHEMA_TABLE query_response_time_table;
+
+#ifdef HAVE_RESPONSE_TIME_DISTRIBUTION
+extern void query_response_time_init ();
+extern void query_response_time_free ();
+extern int query_response_time_flush ();
+extern void query_response_time_collect(ulonglong query_time);
+extern int query_response_time_fill (THD* thd, TABLE_LIST *tables, COND *cond);
+
+extern ulong opt_query_response_time_range_base;
+extern my_bool opt_query_response_time_stats;
+#endif // HAVE_RESPONSE_TIME_DISTRIBUTION
+
+#endif // QUERY_RESPONSE_TIME_H
diff --git a/plugin/server_audit/CMakeLists.txt b/plugin/server_audit/CMakeLists.txt
new file mode 100644
index 00000000..8a5333cf
--- /dev/null
+++ b/plugin/server_audit/CMakeLists.txt
@@ -0,0 +1,18 @@
+# Copyright (C) 2013 Alexey Botchkov and SkySQL Ab
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+SET(SOURCES server_audit.c test_audit_v4.c plugin_audit_v4.h)
+
+MYSQL_ADD_PLUGIN(server_audit ${SOURCES} MODULE_ONLY RECOMPILE_FOR_EMBEDDED)
diff --git a/plugin/server_audit/COPYING b/plugin/server_audit/COPYING
new file mode 100644
index 00000000..6e475df5
--- /dev/null
+++ b/plugin/server_audit/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 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.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, 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 software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, 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 redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+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 give any other recipients of the Program a copy of this License
+along with the Program.
+
+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 Program or any portion
+of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+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 Program, 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 Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) 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; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, 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 executable. 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.
+
+If distribution of executable or 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 counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program 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.
+
+ 5. 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 Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program 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.
+
+ 7. 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 Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program 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 Program.
+
+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.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program 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.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the 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 Program
+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 Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, 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
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), 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 Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. 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 program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/plugin/server_audit/plugin_audit_v4.h b/plugin/server_audit/plugin_audit_v4.h
new file mode 100644
index 00000000..a2a38806
--- /dev/null
+++ b/plugin/server_audit/plugin_audit_v4.h
@@ -0,0 +1,561 @@
+/* Copyright (c) 2007, 2015, 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 the Free Software Foundation; version 2 of
+ the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#ifndef _my_audit_h
+#define _my_audit_h
+
+#ifndef PLUGIN_CONTEXT
+#include "plugin.h"
+#include "mysql/mysql_lex_string.h"
+#ifndef MYSQL_ABI_CHECK
+#include "m_string.h"
+#endif
+#include "my_command.h"
+#include "my_sqlcommand.h"
+#endif /*PLUGIN_CONTEXT*/
+
+#define MYSQL_AUDIT_INTERFACE_VERSION 0x0401
+
+/**
+ @enum mysql_event_class_t
+
+ Audit event classes.
+*/
+typedef enum
+{
+ MYSQL_AUDIT_GENERAL_CLASS = 0,
+ MYSQL_AUDIT_CONNECTION_CLASS = 1,
+ MYSQL_AUDIT_PARSE_CLASS = 2,
+ MYSQL_AUDIT_AUTHORIZATION_CLASS = 3,
+ MYSQL_AUDIT_TABLE_ACCESS_CLASS = 4,
+ MYSQL_AUDIT_GLOBAL_VARIABLE_CLASS = 5,
+ MYSQL_AUDIT_SERVER_STARTUP_CLASS = 6,
+ MYSQL_AUDIT_SERVER_SHUTDOWN_CLASS = 7,
+ MYSQL_AUDIT_COMMAND_CLASS = 8,
+ MYSQL_AUDIT_QUERY_CLASS = 9,
+ MYSQL_AUDIT_STORED_PROGRAM_CLASS = 10,
+ /* This item must be last in the list. */
+ MYSQL_AUDIT_CLASS_MASK_SIZE
+} mysql_event_class_t;
+
+/**
+ @struct st_mysql_audit
+
+ The descriptor structure that is referred from st_mysql_plugin.
+*/
+struct st_mysql_audit
+{
+ /**
+ Interface version.
+ */
+ int interface_version;
+
+ /**
+ Event occurs when the event class consumer is to be
+ disassociated from the specified THD.This would typically occur
+ before some operation which may require sleeping - such as when
+ waiting for the next query from the client.
+ */
+ void (*release_thd)(MYSQL_THD);
+
+ /**
+ Invoked whenever an event occurs which is of any
+ class for which the plugin has interest.The second argument
+ indicates the specific event class and the third argument is data
+ as required for that class.
+ */
+ int (*event_notify)(MYSQL_THD, mysql_event_class_t, const void *);
+
+ /**
+ An array of bits used to indicate what event classes
+ that this plugin wants to receive.
+ */
+ unsigned long class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE];
+};
+
+/**
+ @typedef enum_sql_command_t
+
+ SQL command type definition.
+*/
+typedef enum enum_sql_command enum_sql_command_t;
+
+/**
+ @enum mysql_event_general_subclass_t
+
+ Events for the MYSQL_AUDIT_GENERAL_CLASS event class.
+*/
+typedef enum
+{
+ /** occurs before emitting to the general query log. */
+ MYSQL_AUDIT_GENERAL_LOG = 1 << 0,
+ /** occurs before transmitting errors to the user. */
+ MYSQL_AUDIT_GENERAL_ERROR = 1 << 1,
+ /** occurs after transmitting a resultset to the user. */
+ MYSQL_AUDIT_GENERAL_RESULT = 1 << 2,
+ /** occurs after transmitting a resultset or errors */
+ MYSQL_AUDIT_GENERAL_STATUS = 1 << 3
+} mysql_event_general_subclass_t;
+
+#define MYSQL_AUDIT_GENERAL_ALL (MYSQL_AUDIT_GENERAL_LOG | \
+ MYSQL_AUDIT_GENERAL_ERROR | \
+ MYSQL_AUDIT_GENERAL_RESULT | \
+ MYSQL_AUDIT_GENERAL_STATUS)
+/**
+ @struct mysql_event_general
+
+ Structure for the MYSQL_AUDIT_GENERAL_CLASS event class.
+*/
+struct mysql_event_general
+{
+ mysql_event_general_subclass_t event_subclass;
+ int general_error_code;
+ unsigned long general_thread_id;
+ MYSQL_LEX_CSTRING general_user;
+ MYSQL_LEX_CSTRING general_command;
+ MYSQL_LEX_CSTRING general_query;
+ struct charset_info_st *general_charset;
+ unsigned long long general_time;
+ unsigned long long general_rows;
+ MYSQL_LEX_CSTRING general_host;
+ MYSQL_LEX_CSTRING general_sql_command;
+ MYSQL_LEX_CSTRING general_external_user;
+ MYSQL_LEX_CSTRING general_ip;
+};
+
+/**
+ @enum mysql_event_connection_subclass_t
+
+ Events for MYSQL_AUDIT_CONNECTION_CLASS event class.
+*/
+typedef enum
+{
+ /** occurs after authentication phase is completed. */
+ MYSQL_AUDIT_CONNECTION_CONNECT = 1 << 0,
+ /** occurs after connection is terminated. */
+ MYSQL_AUDIT_CONNECTION_DISCONNECT = 1 << 1,
+ /** occurs after COM_CHANGE_USER RPC is completed. */
+ MYSQL_AUDIT_CONNECTION_CHANGE_USER = 1 << 2,
+ /** occurs before authentication. */
+ MYSQL_AUDIT_CONNECTION_PRE_AUTHENTICATE = 1 << 3
+} mysql_event_connection_subclass_t;
+
+#define MYSQL_AUDIT_CONNECTION_ALL (MYSQL_AUDIT_CONNECTION_CONNECT | \
+ MYSQL_AUDIT_CONNECTION_DISCONNECT | \
+ MYSQL_AUDIT_CONNECTION_CHANGE_USER | \
+ MYSQL_AUDIT_CONNECTION_PRE_AUTHENTICATE)
+/**
+ @struct mysql_event_connection
+
+ Structure for the MYSQL_AUDIT_CONNECTION_CLASS event class.
+*/
+struct mysql_event_connection
+{
+ /** Event subclass. */
+ mysql_event_connection_subclass_t event_subclass;
+ /** Current status of the connection. */
+ int status;
+ /** Connection id. */
+ unsigned long connection_id;
+ /** User name of this connection. */
+ MYSQL_LEX_CSTRING user;
+ /** Priv user name. */
+ MYSQL_LEX_CSTRING priv_user;
+ /** External user name. */
+ MYSQL_LEX_CSTRING external_user;
+ /** Proxy user used for this connection. */
+ MYSQL_LEX_CSTRING proxy_user;
+ /** Connection host. */
+ MYSQL_LEX_CSTRING host;
+ /** IP of the connection. */
+ MYSQL_LEX_CSTRING ip;
+ /** Database name specified at connection time. */
+ MYSQL_LEX_CSTRING database;
+ /** Connection type:
+ - 0 Undefined
+ - 1 TCP/IP
+ - 2 Socket
+ - 3 Named pipe
+ - 4 SSL
+ - 5 Shared memory
+ */
+ int connection_type;
+};
+
+/**
+@enum mysql_event_parse_subclass_t
+
+Events for MYSQL_AUDIT_PARSE_CLASS event class.
+*/
+typedef enum
+{
+ /** occurs before the query parsing. */
+ MYSQL_AUDIT_PARSE_PREPARSE = 1 << 0,
+ /** occurs after the query parsing. */
+ MYSQL_AUDIT_PARSE_POSTPARSE = 1 << 1
+} mysql_event_parse_subclass_t;
+
+#define MYSQL_AUDIT_PARSE_ALL (MYSQL_AUDIT_PARSE_PREPARSE | \
+ MYSQL_AUDIT_PARSE_POSTPARSE)
+
+typedef enum
+{
+ MYSQL_AUDIT_PARSE_REWRITE_PLUGIN_NONE = 0,
+ /// mysql_event_parse::flags Must be set by a plugin if the query is rewritten.
+ MYSQL_AUDIT_PARSE_REWRITE_PLUGIN_QUERY_REWRITTEN = 1 << 0,
+ /// mysql_event_parse::flags Is set by the server if the query is prepared statement.
+ MYSQL_AUDIT_PARSE_REWRITE_PLUGIN_IS_PREPARED_STATEMENT = 1 << 1
+} mysql_event_parse_rewrite_plugin_flag;
+
+/** Data for the MYSQL_AUDIT_PARSE events */
+struct mysql_event_parse
+{
+ /** MYSQL_AUDIT_[PRE|POST]_PARSE event id */
+ mysql_event_parse_subclass_t event_subclass;
+
+ /** one of FLAG_REWRITE_PLUGIN_* */
+ mysql_event_parse_rewrite_plugin_flag *flags;
+
+ /** input: the original query text */
+ MYSQL_LEX_CSTRING query;
+
+ /** output: returns the null-terminated rewritten query allocated by my_malloc() */
+ MYSQL_LEX_CSTRING *rewritten_query;
+};
+
+/**
+ @enum mysql_event_authorization_subclass_t
+
+ Events for MYSQL_AUDIT_AUTHORIZATION_CLASS event class.
+*/
+typedef enum
+{
+ MYSQL_AUDIT_AUTHORIZATION_USER = 1 << 0,
+ /** Occurs when database privilege is checked. */
+ MYSQL_AUDIT_AUTHORIZATION_DB = 1 << 1,
+ /** Occurs when table privilege is checked. */
+ MYSQL_AUDIT_AUTHORIZATION_TABLE = 1 << 2,
+ /** Occurs when column privilege is checked. */
+ MYSQL_AUDIT_AUTHORIZATION_COLUMN = 1 << 3,
+ /** Occurs when procedure privilege is checked. */
+ MYSQL_AUDIT_AUTHORIZATION_PROCEDURE = 1 << 4,
+ /** Occurs when proxy privilege is checked. */
+ MYSQL_AUDIT_AUTHORIZATION_PROXY = 1 << 5
+} mysql_event_authorization_subclass_t;
+
+#define MYSQL_AUDIT_AUTHORIZATION_ALL (MYSQL_AUDIT_AUTHORIZATION_USER | \
+ MYSQL_AUDIT_AUTHORIZATION_DB | \
+ MYSQL_AUDIT_AUTHORIZATION_TABLE | \
+ MYSQL_AUDIT_AUTHORIZATION_COLUMN | \
+ MYSQL_AUDIT_AUTHORIZATION_PROCEDURE | \
+ MYSQL_AUDIT_AUTHORIZATION_PROXY)
+/**
+ @struct mysql_event_authorization
+
+ Structure for MYSQL_AUDIT_AUTHORIZATION_CLASS event class.
+*/
+struct mysql_event_authorization
+{
+ /** Event subclass. */
+ mysql_event_authorization_subclass_t event_subclass;
+ /** Event status. */
+ int status;
+ /** Connection id. */
+ unsigned int connection_id;
+ /** SQL command id. */
+ enum_sql_command_t sql_command_id;
+ /** SQL query text. */
+ MYSQL_LEX_CSTRING query;
+ /** SQL query charset. */
+ const struct charset_info_st *query_charset;
+ /** Database name. */
+ MYSQL_LEX_CSTRING database;
+ /** Table name. */
+ MYSQL_LEX_CSTRING table;
+ /** Other name associated with the event. */
+ MYSQL_LEX_CSTRING object;
+ /** Requested authorization privileges. */
+ unsigned long requested_privilege;
+ /** Currently granted authorization privileges. */
+ unsigned long granted_privilege;
+};
+
+/**
+ @enum mysql_event_table_row_access_subclass_t
+
+ Events for MYSQL_AUDIT_TABLE_ACCES_CLASS event class.
+*/
+typedef enum
+{
+ /** Occurs when table data are read. */
+ MYSQL_AUDIT_TABLE_ACCESS_READ = 1 << 0,
+ /** Occurs when table data are inserted. */
+ MYSQL_AUDIT_TABLE_ACCESS_INSERT = 1 << 1,
+ /** Occurs when table data are updated. */
+ MYSQL_AUDIT_TABLE_ACCESS_UPDATE = 1 << 2,
+ /** Occurs when table data are deleted. */
+ MYSQL_AUDIT_TABLE_ACCESS_DELETE = 1 << 3
+} mysql_event_table_access_subclass_t;
+
+#define MYSQL_AUDIT_TABLE_ACCESS_ALL (MYSQL_AUDIT_TABLE_ACCESS_READ | \
+ MYSQL_AUDIT_TABLE_ACCESS_INSERT | \
+ MYSQL_AUDIT_TABLE_ACCESS_UPDATE | \
+ MYSQL_AUDIT_TABLE_ACCESS_DELETE)
+
+/**
+ @struct mysql_event_table_row_access
+
+ Structure for MYSQL_AUDIT_TABLE_ACCES_CLASS event class.
+*/
+struct mysql_event_table_access
+{
+ /** Event subclass. */
+ mysql_event_table_access_subclass_t event_subclass;
+ /** Connection id. */
+ unsigned long connection_id;
+ /** SQL command id. */
+ enum_sql_command_t sql_command_id;
+ /** SQL query. */
+ MYSQL_LEX_CSTRING query;
+ /** SQL query charset. */
+ const struct charset_info_st *query_charset;
+ /** Database name. */
+ MYSQL_LEX_CSTRING table_database;
+ /** Table name. */
+ MYSQL_LEX_CSTRING table_name;
+};
+
+/**
+ @enum mysql_event_global_variable_subclass_t
+
+ Events for MYSQL_AUDIT_GLOBAL_VARIABLE_CLASS event class.
+*/
+typedef enum
+{
+ /** Occurs when global variable is retrieved. */
+ MYSQL_AUDIT_GLOBAL_VARIABLE_GET = 1 << 0,
+ /** Occurs when global variable is set. */
+ MYSQL_AUDIT_GLOBAL_VARIABLE_SET = 1 << 1
+} mysql_event_global_variable_subclass_t;
+
+#define MYSQL_AUDIT_GLOBAL_VARIABLE_ALL (MYSQL_AUDIT_GLOBAL_VARIABLE_GET | \
+ MYSQL_AUDIT_GLOBAL_VARIABLE_SET)
+
+/** Events for MYSQL_AUDIT_GLOBAL_VARIABLE_CLASS event class. */
+struct mysql_event_global_variable
+{
+ /** Event subclass. */
+ mysql_event_global_variable_subclass_t event_subclass;
+ /** Connection id. */
+ unsigned long connection_id;
+ /** SQL command id. */
+ enum_sql_command_t sql_command_id;
+ /** Variable name. */
+ MYSQL_LEX_CSTRING variable_name;
+ /** Variable value. */
+ MYSQL_LEX_CSTRING variable_value;
+};
+
+/**
+ @enum mysql_event_server_startup_subclass_t
+
+ Events for MYSQL_AUDIT_SERVER_STARTUP_CLASS event class.
+*/
+typedef enum
+{
+ /** Occurs after all subsystem are initialized during system start. */
+ MYSQL_AUDIT_SERVER_STARTUP_STARTUP = 1 << 0
+} mysql_event_server_startup_subclass_t;
+
+#define MYSQL_AUDIT_SERVER_STARTUP_ALL (MYSQL_AUDIT_SERVER_STARTUP_STARTUP)
+
+/**
+ @struct mysql_event_server_startup
+
+ Structure for MYSQL_AUDIT_SERVER_STARTUP_CLASS event class.
+*/
+struct mysql_event_server_startup
+{
+ /** Event subclass. */
+ mysql_event_server_startup_subclass_t event_subclass;
+ /** Command line arguments. */
+ const char **argv;
+ /** Command line arguments count. */
+ unsigned int argc;
+};
+
+/**
+ @enum mysql_event_server_shutdown_subclass_t
+
+ Events for MYSQL_AUDIT_SERVER_SHUTDOWN_CLASS event class.
+*/
+typedef enum
+{
+ /** Occurs when global variable is set. */
+ MYSQL_AUDIT_SERVER_SHUTDOWN_SHUTDOWN = 1 << 0
+} mysql_event_server_shutdown_subclass_t;
+
+#define MYSQL_AUDIT_SERVER_SHUTDOWN_ALL (MYSQL_AUDIT_SERVER_SHUTDOWN_SHUTDOWN)
+
+/**
+ @enum mysql_server_shutdown_reason_t
+
+ Server shutdown reason.
+*/
+typedef enum
+{
+ /** User requested shut down. */
+ MYSQL_AUDIT_SERVER_SHUTDOWN_REASON_SHUTDOWN,
+ /** The server aborts. */
+ MYSQL_AUDIT_SERVER_SHUTDOWN_REASON_ABORT
+} mysql_server_shutdown_reason_t;
+
+/**
+ @struct mysql_event_server_shutdown
+
+ Structure for MYSQL_AUDIT_SERVER_SHUTDOWN_CLASS event class.
+*/
+struct mysql_event_server_shutdown
+{
+ /** Shutdown event. */
+ mysql_event_server_shutdown_subclass_t event_subclass;
+ /** Exit code associated with the shutdown event. */
+ int exit_code;
+ /** Shutdown reason. */
+ mysql_server_shutdown_reason_t reason;
+};
+
+/**
+ @enum mysql_event_command_subclass_t
+
+ Events for MYSQL_AUDIT_COMMAND_CLASS event class.
+*/
+typedef enum
+{
+ /** Command start event. */
+ MYSQL_AUDIT_COMMAND_START = 1 << 0,
+ /** Command end event. */
+ MYSQL_AUDIT_COMMAND_END = 1 << 1
+} mysql_event_command_subclass_t;
+
+#define MYSQL_AUDIT_COMMAND_ALL (MYSQL_AUDIT_COMMAND_START | \
+ MYSQL_AUDIT_COMMAND_END)
+/**
+ @typedef enum_server_command_t
+
+ Server command type definition.
+*/
+typedef enum enum_server_command enum_server_command_t;
+
+/**
+ @struct mysql_event_command
+
+ Event for MYSQL_AUDIT_COMMAND_CLASS event class.
+ Events generated as a result of RPC command requests.
+*/
+struct mysql_event_command
+{
+ /** Command event subclass. */
+ mysql_event_command_subclass_t event_subclass;
+ /** Command event status. */
+ int status;
+ /** Connection id. */
+ unsigned long connection_id;
+ /** Command id. */
+ enum_server_command_t command_id;
+};
+
+/**
+ @enum mysql_event_query_subclass_t
+
+ Events for MYSQL_AUDIT_QUERY_CLASS event class.
+*/
+typedef enum
+{
+ /** Query start event. */
+ MYSQL_AUDIT_QUERY_START = 1 << 0,
+ /** Nested query start event. */
+ MYSQL_AUDIT_QUERY_NESTED_START = 1 << 1,
+ /** Query post parse event. */
+ MYSQL_AUDIT_QUERY_STATUS_END = 1 << 2,
+ /** Nested query status end event. */
+ MYSQL_AUDIT_QUERY_NESTED_STATUS_END = 1 << 3
+} mysql_event_query_subclass_t;
+
+#define MYSQL_AUDIT_QUERY_ALL (MYSQL_AUDIT_QUERY_START | \
+ MYSQL_AUDIT_QUERY_NESTED_START | \
+ MYSQL_AUDIT_QUERY_STATUS_END | \
+ MYSQL_AUDIT_QUERY_NESTED_STATUS_END)
+/**
+ @struct mysql_event_command
+
+ Event for MYSQL_AUDIT_COMMAND_CLASS event class.
+*/
+struct mysql_event_query
+{
+ /** Event subclass. */
+ mysql_event_query_subclass_t event_subclass;
+ /** Event status. */
+ int status;
+ /** Connection id. */
+ unsigned long connection_id;
+ /** SQL command id. */
+ enum_sql_command_t sql_command_id;
+ /** SQL query. */
+ MYSQL_LEX_CSTRING query;
+ /** SQL query charset. */
+ const struct charset_info_st *query_charset;
+};
+
+/**
+ @enum mysql_event_stored_program_subclass_t
+
+ Events for MYSQL_AUDIT_STORED_PROGRAM_CLASS event class.
+*/
+typedef enum
+{
+ /** Stored program execution event. */
+ MYSQL_AUDIT_STORED_PROGRAM_EXECUTE = 1 << 0
+} mysql_event_stored_program_subclass_t;
+
+#define MYSQL_AUDIT_STORED_PROGRAM_ALL (MYSQL_AUDIT_STORED_PROGRAM_EXECUTE)
+
+/**
+ @struct mysql_event_command
+
+Event for MYSQL_AUDIT_COMMAND_CLASS event class.
+*/
+struct mysql_event_stored_program
+{
+ /** Event subclass. */
+ mysql_event_stored_program_subclass_t event_subclass;
+ /** Connection id. */
+ unsigned long connection_id;
+ /** SQL command id. */
+ enum_sql_command_t sql_command_id;
+ /** SQL query text. */
+ MYSQL_LEX_CSTRING query;
+ /** SQL query charset. */
+ const struct charset_info_st *query_charset;
+ /** The Database the procedure is defined in. */
+ MYSQL_LEX_CSTRING database;
+ /** Name of the stored program. */
+ MYSQL_LEX_CSTRING name;
+ /** Stored program parameters. */
+ void *parameters;
+};
+
+#endif
diff --git a/plugin/server_audit/server_audit.c b/plugin/server_audit/server_audit.c
new file mode 100644
index 00000000..e94361de
--- /dev/null
+++ b/plugin/server_audit/server_audit.c
@@ -0,0 +1,3104 @@
+/* Copyright (C) 2013, 2015, Alexey Botchkov and SkySQL Ab
+ Copyright (c) 2019, 2020, MariaDB Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+
+#define PLUGIN_VERSION 0x104
+#define PLUGIN_STR_VERSION "1.4.13"
+
+#define _my_thread_var loc_thread_var
+
+#include <my_config.h>
+#include <assert.h>
+
+#ifndef _WIN32
+#define DO_SYSLOG
+#include <syslog.h>
+static const char out_type_desc[]= "Desired output type. Possible values - 'syslog', 'file'"
+ " or 'null' as no output.";
+#else
+static const char out_type_desc[]= "Desired output type. Possible values - 'file'"
+ " or 'null' as no output.";
+#define syslog(PRIORITY, FORMAT, INFO, MESSAGE_LEN, MESSAGE) do {}while(0)
+static void closelog() {}
+#define openlog(IDENT, LOG_NOWAIT, LOG_USER) do {}while(0)
+
+/* priorities */
+#define LOG_EMERG 0 /* system is unusable */
+#define LOG_ALERT 1 /* action must be taken immediately */
+#define LOG_CRIT 2 /* critical conditions */
+#define LOG_ERR 3 /* error conditions */
+#define LOG_WARNING 4 /* warning conditions */
+#define LOG_NOTICE 5 /* normal but significant condition */
+#define LOG_INFO 6 /* informational */
+#define LOG_DEBUG 7 /* debug-level messages */
+
+#define LOG_MAKEPRI(fac, pri) (((fac) << 3) | (pri))
+
+/* facility codes */
+#define LOG_KERN (0<<3) /* kernel messages */
+#define LOG_USER (1<<3) /* random user-level messages */
+#define LOG_MAIL (2<<3) /* mail system */
+#define LOG_DAEMON (3<<3) /* system daemons */
+#define LOG_AUTH (4<<3) /* security/authorization messages */
+#define LOG_SYSLOG (5<<3) /* messages generated internally by syslogd */
+#define LOG_LPR (6<<3) /* line printer subsystem */
+#define LOG_NEWS (7<<3) /* network news subsystem */
+#define LOG_UUCP (8<<3) /* UUCP subsystem */
+#define LOG_CRON (9<<3) /* clock daemon */
+#define LOG_AUTHPRIV (10<<3) /* security/authorization messages (private) */
+#define LOG_FTP (11<<3) /* ftp daemon */
+#define LOG_LOCAL0 (16<<3) /* reserved for local use */
+#define LOG_LOCAL1 (17<<3) /* reserved for local use */
+#define LOG_LOCAL2 (18<<3) /* reserved for local use */
+#define LOG_LOCAL3 (19<<3) /* reserved for local use */
+#define LOG_LOCAL4 (20<<3) /* reserved for local use */
+#define LOG_LOCAL5 (21<<3) /* reserved for local use */
+#define LOG_LOCAL6 (22<<3) /* reserved for local use */
+#define LOG_LOCAL7 (23<<3) /* reserved for local use */
+
+#endif /*!_WIN32*/
+
+/*
+ Defines that can be used to reshape the pluging:
+ #define MARIADB_ONLY
+ #define USE_MARIA_PLUGIN_INTERFACE
+*/
+
+#if !defined(MYSQL_DYNAMIC_PLUGIN) && !defined(MARIADB_ONLY)
+#include <typelib.h>
+#define MARIADB_ONLY
+#endif /*MYSQL_PLUGIN_DYNAMIC*/
+
+#ifndef MARIADB_ONLY
+#define MYSQL_SERVICE_LOGGER_INCLUDED
+#endif /*MARIADB_ONLY*/
+
+#include <my_global.h>
+#include <my_base.h>
+#include <typelib.h>
+#include <mysql/plugin.h>
+#include <mysql/plugin_audit.h>
+#include <string.h>
+#include "../../mysys/mysys_priv.h"
+#ifndef RTLD_DEFAULT
+#define RTLD_DEFAULT NULL
+#endif
+
+#ifndef MARIADB_ONLY
+#undef MYSQL_SERVICE_LOGGER_INCLUDED
+#undef MYSQL_DYNAMIC_PLUGIN
+#define FLOGGER_NO_PSI
+
+/* How to access the pthread_mutex in mysql_mutex_t */
+#ifdef SAFE_MUTEX
+#define mysql_mutex_real_mutex(A) &(A)->m_mutex.mutex
+#else
+#define mysql_mutex_real_mutex(A) &(A)->m_mutex
+#endif
+
+#define flogger_mutex_init(A,B,C) do{}while(0)
+#define flogger_mutex_destroy(A) do{}while(0)
+#define flogger_mutex_lock(A) do{}while(0)
+#define flogger_mutex_unlock(A) do{}while(0)
+
+static char **int_mysql_data_home;
+static char *default_home= (char *)".";
+#define mysql_data_home (*int_mysql_data_home)
+
+#define FLOGGER_SKIP_INCLUDES
+#define my_open(A, B, C) loc_open(A, B)
+#define my_close(A, B) loc_close(A)
+#define my_rename(A, B, C) loc_rename(A, B)
+#define my_tell(A, B) loc_tell(A)
+#define my_write(A, B, C, D) loc_write(A, B, C)
+#define my_malloc(A, B, C) malloc(B)
+#define my_free(A) free(A)
+#ifdef my_errno
+ #undef my_errno
+#endif
+static int loc_file_errno;
+#define my_errno loc_file_errno
+#ifdef my_vsnprintf
+ #undef my_vsnprintf
+#endif
+#define my_vsnprintf vsnprintf
+#define logger_open loc_logger_open
+#define logger_close loc_logger_close
+#define logger_write loc_logger_write
+#define logger_rotate loc_logger_rotate
+#define logger_init_mutexts loc_logger_init_mutexts
+#define logger_time_to_rotate loc_logger_time_to_rotate
+
+
+static size_t loc_write(File Filedes, const uchar *Buffer, size_t Count)
+{
+ size_t writtenbytes;
+#ifdef _WIN32
+ writtenbytes= (size_t)_write(Filedes, Buffer, (unsigned int)Count);
+#else
+ writtenbytes= write(Filedes, Buffer, Count);
+#endif
+ return writtenbytes;
+}
+
+
+static File loc_open(const char *FileName, int Flags)
+ /* Path-name of file */
+ /* Read | write .. */
+ /* Special flags */
+{
+ File fd;
+#ifdef _WIN32
+ HANDLE h;
+ /*
+ We could just use _open() here. but prefer to open in unix-similar way
+ just like my_open() does it on Windows.
+ This gives atomic multiprocess-safe appends, and possibility to rename
+ or even delete file while it is open, and CRT lacks this features.
+ */
+ assert(Flags == (O_APPEND | O_CREAT | O_WRONLY));
+ h= CreateFile(FileName, FILE_APPEND_DATA,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL,
+ OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (h == INVALID_HANDLE_VALUE)
+ {
+ fd= -1;
+ my_osmaperr(GetLastError());
+ }
+ else
+ {
+ fd= _open_osfhandle((intptr)h, O_WRONLY|O_BINARY);
+ }
+#else
+ fd= open(FileName, Flags, my_umask);
+#endif
+ my_errno= errno;
+ return fd;
+}
+
+
+static int loc_close(File fd)
+{
+ int err;
+#ifndef _WIN32
+ do
+ {
+ err= close(fd);
+ } while (err == -1 && errno == EINTR);
+#else
+ err= close(fd);
+#endif
+ my_errno=errno;
+ return err;
+}
+
+
+static int loc_rename(const char *from, const char *to)
+{
+ int error = 0;
+
+#if defined(__WIN__)
+ if (!MoveFileEx(from, to, MOVEFILE_COPY_ALLOWED |
+ MOVEFILE_REPLACE_EXISTING))
+ {
+ my_osmaperr(GetLastError());
+#elif defined(HAVE_RENAME)
+ if (rename(from,to))
+ {
+#else
+ if (link(from, to) || unlink(from))
+ {
+#endif
+ my_errno=errno;
+ error = -1;
+ }
+ return error;
+}
+
+
+static my_off_t loc_tell(File fd)
+{
+ os_off_t pos= IF_WIN(_telli64(fd),lseek(fd, 0, SEEK_CUR));
+ if (pos == (os_off_t) -1)
+ {
+ my_errno= errno;
+ }
+ return (my_off_t) pos;
+}
+
+#ifdef HAVE_PSI_INTERFACE
+#undef HAVE_PSI_INTERFACE
+#include <mysql/service_logger.h>
+#include "../../mysys/file_logger.c"
+#define HAVE_PSI_INTERFACE
+#else
+#include <mysql/service_logger.h>
+#include "../../mysys/file_logger.c"
+#endif
+#endif /*!MARIADB_ONLY*/
+
+#undef flogger_mutex_init
+#undef flogger_mutex_destroy
+#undef flogger_mutex_lock
+#undef flogger_mutex_unlock
+
+#define flogger_mutex_init(A,B,C) pthread_mutex_init(mysql_mutex_real_mutex(B), C)
+#define flogger_mutex_destroy(A) pthread_mutex_destroy(mysql_mutex_real_mutex(A))
+#define flogger_mutex_lock(A) pthread_mutex_lock(mysql_mutex_real_mutex(A))
+#define flogger_mutex_unlock(A) pthread_mutex_unlock(mysql_mutex_real_mutex(A))
+
+#ifndef DBUG_OFF
+#define PLUGIN_DEBUG_VERSION "-debug"
+#else
+#define PLUGIN_DEBUG_VERSION ""
+#endif /*DBUG_OFF*/
+/*
+ Disable __attribute__() on non-gcc compilers.
+*/
+#if !defined(__attribute__) && !defined(__GNUC__)
+#define __attribute__(A)
+#endif
+
+#ifdef _WIN32
+#define localtime_r(a, b) localtime_s(b, a)
+#endif /*WIN32*/
+
+
+extern MYSQL_PLUGIN_IMPORT char server_version[];
+static const char *serv_ver= NULL;
+static int started_mysql= 0;
+static int mysql_57_started= 0;
+static int debug_server_started= 0;
+static int use_event_data_for_disconnect= 0;
+static int started_mariadb= 0;
+static int maria_55_started= 0;
+static int maria_above_5= 0;
+static char *incl_users, *excl_users,
+ *file_path, *syslog_info;
+static char path_buffer[FN_REFLEN];
+static unsigned int mode, mode_readonly= 0;
+static ulong output_type;
+static ulong syslog_facility, syslog_priority;
+
+static ulonglong events; /* mask for events to log */
+static unsigned long long file_rotate_size;
+static unsigned int rotations;
+static my_bool rotate= TRUE;
+static char logging;
+static volatile int internal_stop_logging= 0;
+static char incl_user_buffer[1024];
+static char excl_user_buffer[1024];
+static char *big_buffer= NULL;
+static size_t big_buffer_alloced= 0;
+static unsigned int query_log_limit= 0;
+
+static char servhost[256];
+static uint servhost_len;
+static char *syslog_ident;
+static char syslog_ident_buffer[128]= "mysql-server_auditing";
+
+struct connection_info
+{
+ int header;
+ unsigned long thread_id;
+ unsigned long long query_id;
+ char db[256];
+ int db_length;
+ char user[64];
+ int user_length;
+ char host[64];
+ int host_length;
+ char ip[64];
+ int ip_length;
+ const char *query;
+ int query_length;
+ char query_buffer[1024];
+ time_t query_time;
+ int log_always;
+ char proxy[64];
+ int proxy_length;
+ char proxy_host[64];
+ int proxy_host_length;
+};
+
+#define DEFAULT_FILENAME_LEN 16
+static char default_file_name[DEFAULT_FILENAME_LEN+1]= "server_audit.log";
+
+static void update_file_path(MYSQL_THD thd, struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save);
+static void update_file_rotate_size(MYSQL_THD thd, struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save);
+static void update_file_rotations(MYSQL_THD thd, struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save);
+static void update_incl_users(MYSQL_THD thd, struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save);
+static int check_incl_users(MYSQL_THD thd, struct st_mysql_sys_var *var, void *save,
+ struct st_mysql_value *value);
+static int check_excl_users(MYSQL_THD thd, struct st_mysql_sys_var *var, void *save,
+ struct st_mysql_value *value);
+static void update_excl_users(MYSQL_THD thd, struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save);
+static void update_output_type(MYSQL_THD thd, struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save);
+static void update_syslog_facility(MYSQL_THD thd, struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save);
+static void update_syslog_priority(MYSQL_THD thd, struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save);
+static void update_mode(MYSQL_THD thd, struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save);
+static void update_logging(MYSQL_THD thd, struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save);
+static void update_syslog_ident(MYSQL_THD thd, struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save);
+static void rotate_log(MYSQL_THD thd, struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save);
+
+static MYSQL_SYSVAR_STR(incl_users, incl_users, PLUGIN_VAR_RQCMDARG,
+ "Comma separated list of users to monitor.",
+ check_incl_users, update_incl_users, NULL);
+static MYSQL_SYSVAR_STR(excl_users, excl_users, PLUGIN_VAR_RQCMDARG,
+ "Comma separated list of users to exclude from auditing.",
+ check_excl_users, update_excl_users, NULL);
+/* bits in the event filter. */
+#define EVENT_CONNECT 1
+#define EVENT_QUERY_ALL 2
+#define EVENT_QUERY 122
+#define EVENT_TABLE 4
+#define EVENT_QUERY_DDL 8
+#define EVENT_QUERY_DML 16
+#define EVENT_QUERY_DCL 32
+#define EVENT_QUERY_DML_NO_SELECT 64
+
+static const char *event_names[]=
+{
+ "CONNECT", "QUERY", "TABLE", "QUERY_DDL", "QUERY_DML", "QUERY_DCL",
+ "QUERY_DML_NO_SELECT", NULL
+};
+static TYPELIB events_typelib=
+{
+ array_elements(event_names) - 1, "", event_names, NULL
+};
+static MYSQL_SYSVAR_SET(events, events, PLUGIN_VAR_RQCMDARG,
+ "Specifies the set of events to monitor. Can be CONNECT, QUERY, TABLE,"
+ " QUERY_DDL, QUERY_DML, QUERY_DML_NO_SELECT, QUERY_DCL.",
+ NULL, NULL, 0, &events_typelib);
+#ifdef DO_SYSLOG
+#define OUTPUT_SYSLOG 0
+#define OUTPUT_FILE 1
+#else
+#define OUTPUT_SYSLOG 0xFFFF
+#define OUTPUT_FILE 0
+#endif /*DO_SYSLOG*/
+
+#define OUTPUT_NO 0xFFFF
+static const char *output_type_names[]= {
+#ifdef DO_SYSLOG
+ "syslog",
+#endif
+ "file", 0 };
+static TYPELIB output_typelib=
+{
+ array_elements(output_type_names) - 1, "output_typelib",
+ output_type_names, NULL
+};
+static MYSQL_SYSVAR_ENUM(output_type, output_type, PLUGIN_VAR_RQCMDARG,
+ out_type_desc,
+ 0, update_output_type, OUTPUT_FILE,
+ &output_typelib);
+static MYSQL_SYSVAR_STR(file_path, file_path, PLUGIN_VAR_RQCMDARG,
+ "Path to the log file.", NULL, update_file_path, default_file_name);
+static MYSQL_SYSVAR_ULONGLONG(file_rotate_size, file_rotate_size,
+ PLUGIN_VAR_RQCMDARG, "Maximum size of the log to start the rotation.",
+ NULL, update_file_rotate_size,
+ 1000000, 100, ((long long) 0x7FFFFFFFFFFFFFFFLL), 1);
+static MYSQL_SYSVAR_UINT(file_rotations, rotations,
+ PLUGIN_VAR_RQCMDARG, "Number of rotations before log is removed.",
+ NULL, update_file_rotations, 9, 0, 999, 1);
+static MYSQL_SYSVAR_BOOL(file_rotate_now, rotate, PLUGIN_VAR_OPCMDARG,
+ "Force log rotation now.", NULL, rotate_log, FALSE);
+static MYSQL_SYSVAR_BOOL(logging, logging,
+ PLUGIN_VAR_OPCMDARG, "Turn on/off the logging.", NULL,
+ update_logging, 0);
+static MYSQL_SYSVAR_UINT(mode, mode,
+ PLUGIN_VAR_OPCMDARG, "Auditing mode.", NULL, update_mode, 0, 0, 1, 1);
+static MYSQL_SYSVAR_STR(syslog_ident, syslog_ident, PLUGIN_VAR_RQCMDARG,
+ "The SYSLOG identifier - the beginning of each SYSLOG record.",
+ NULL, update_syslog_ident, syslog_ident_buffer);
+static MYSQL_SYSVAR_STR(syslog_info, syslog_info,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
+ "The <info> string to be added to the SYSLOG record.", NULL, NULL, "");
+static MYSQL_SYSVAR_UINT(query_log_limit, query_log_limit,
+ PLUGIN_VAR_OPCMDARG, "Limit on the length of the query string in a record.",
+ NULL, NULL, 1024, 0, 0x7FFFFFFF, 1);
+
+char locinfo_ini_value[sizeof(struct connection_info)+4];
+
+static MYSQL_THDVAR_STR(loc_info,
+ PLUGIN_VAR_NOSYSVAR | PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_MEMALLOC,
+ "Internal info", NULL, NULL, locinfo_ini_value);
+
+static const char *syslog_facility_names[]=
+{
+ "LOG_USER", "LOG_MAIL", "LOG_DAEMON", "LOG_AUTH",
+ "LOG_SYSLOG", "LOG_LPR", "LOG_NEWS", "LOG_UUCP",
+ "LOG_CRON",
+#ifdef LOG_AUTHPRIV
+ "LOG_AUTHPRIV",
+#endif
+#ifdef LOG_FTP
+ "LOG_FTP",
+#endif
+ "LOG_LOCAL0", "LOG_LOCAL1", "LOG_LOCAL2", "LOG_LOCAL3",
+ "LOG_LOCAL4", "LOG_LOCAL5", "LOG_LOCAL6", "LOG_LOCAL7",
+ 0
+};
+#ifndef _WIN32
+static unsigned int syslog_facility_codes[]=
+{
+ LOG_USER, LOG_MAIL, LOG_DAEMON, LOG_AUTH,
+ LOG_SYSLOG, LOG_LPR, LOG_NEWS, LOG_UUCP,
+ LOG_CRON,
+#ifdef LOG_AUTHPRIV
+ LOG_AUTHPRIV,
+#endif
+#ifdef LOG_FTP
+ LOG_FTP,
+#endif
+ LOG_LOCAL0, LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3,
+ LOG_LOCAL4, LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7,
+};
+#endif
+static TYPELIB syslog_facility_typelib=
+{
+ array_elements(syslog_facility_names) - 1, "syslog_facility_typelib",
+ syslog_facility_names, NULL
+};
+static MYSQL_SYSVAR_ENUM(syslog_facility, syslog_facility, PLUGIN_VAR_RQCMDARG,
+ "The 'facility' parameter of the SYSLOG record."
+ " The default is LOG_USER.", 0, update_syslog_facility, 0/*LOG_USER*/,
+ &syslog_facility_typelib);
+
+static const char *syslog_priority_names[]=
+{
+ "LOG_EMERG", "LOG_ALERT", "LOG_CRIT", "LOG_ERR",
+ "LOG_WARNING", "LOG_NOTICE", "LOG_INFO", "LOG_DEBUG",
+ 0
+};
+
+#ifndef _WIN32
+static unsigned int syslog_priority_codes[]=
+{
+ LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR,
+ LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG,
+};
+#endif
+
+static TYPELIB syslog_priority_typelib=
+{
+ array_elements(syslog_priority_names) - 1, "syslog_priority_typelib",
+ syslog_priority_names, NULL
+};
+static MYSQL_SYSVAR_ENUM(syslog_priority, syslog_priority, PLUGIN_VAR_RQCMDARG,
+ "The 'priority' parameter of the SYSLOG record."
+ " The default is LOG_INFO.", 0, update_syslog_priority, 6/*LOG_INFO*/,
+ &syslog_priority_typelib);
+
+
+static struct st_mysql_sys_var* vars[] = {
+ MYSQL_SYSVAR(incl_users),
+ MYSQL_SYSVAR(excl_users),
+ MYSQL_SYSVAR(events),
+ MYSQL_SYSVAR(output_type),
+ MYSQL_SYSVAR(file_path),
+ MYSQL_SYSVAR(file_rotate_size),
+ MYSQL_SYSVAR(file_rotations),
+ MYSQL_SYSVAR(file_rotate_now),
+ MYSQL_SYSVAR(logging),
+ MYSQL_SYSVAR(mode),
+ MYSQL_SYSVAR(syslog_info),
+ MYSQL_SYSVAR(syslog_ident),
+ MYSQL_SYSVAR(syslog_facility),
+ MYSQL_SYSVAR(syslog_priority),
+ MYSQL_SYSVAR(query_log_limit),
+ MYSQL_SYSVAR(loc_info),
+ NULL
+};
+
+
+/* Status variables for SHOW STATUS */
+static int is_active= 0;
+static long log_write_failures= 0;
+static char current_log_buf[FN_REFLEN]= "";
+static char last_error_buf[512]= "";
+
+extern void *mysql_v4_descriptor;
+
+static struct st_mysql_show_var audit_status[]=
+{
+ {"server_audit_active", (char *)&is_active, SHOW_BOOL},
+ {"server_audit_current_log", current_log_buf, SHOW_CHAR},
+ {"server_audit_writes_failed", (char *)&log_write_failures, SHOW_LONG},
+ {"server_audit_last_error", last_error_buf, SHOW_CHAR},
+ {0,0,0}
+};
+
+#ifdef HAVE_PSI_INTERFACE
+static PSI_mutex_key key_LOCK_operations;
+static PSI_mutex_info mutex_key_list[]=
+{
+ { &key_LOCK_operations, "SERVER_AUDIT_plugin::lock_operations",
+ PSI_FLAG_GLOBAL}
+#ifndef FLOGGER_NO_PSI
+ ,
+ { &key_LOCK_atomic, "SERVER_AUDIT_plugin::lock_atomic",
+ PSI_FLAG_GLOBAL},
+ { &key_LOCK_bigbuffer, "SERVER_AUDIT_plugin::lock_bigbuffer",
+ PSI_FLAG_GLOBAL}
+#endif /*FLOGGER_NO_PSI*/
+};
+#endif /*HAVE_PSI_INTERFACE*/
+static mysql_prlock_t lock_operations;
+static mysql_mutex_t lock_atomic;
+static mysql_mutex_t lock_bigbuffer;
+
+/* The Percona server and partly MySQL don't support */
+/* launching client errors in the 'update_variable' methods. */
+/* So the client errors just disabled for them. */
+/* The possible solution is to implement the 'check_variable'*/
+/* methods there properly, but at the moment i'm not sure it */
+/* worths doing. */
+#define CLIENT_ERROR if (!started_mysql) my_printf_error
+
+#define ADD_ATOMIC(x, a) \
+ do { \
+ flogger_mutex_lock(&lock_atomic); \
+ x+= a; \
+ flogger_mutex_unlock(&lock_atomic); \
+ } while (0)
+
+
+static uchar *getkey_user(const char *entry, size_t *length,
+ my_bool nu __attribute__((unused)) )
+{
+ const char *e= entry;
+ while (*e && *e != ' ' && *e != ',')
+ ++e;
+ *length= e - entry;
+ return (uchar *) entry;
+}
+
+
+static void blank_user(char *user)
+{
+ for (; *user && *user != ','; user++)
+ *user= ' ';
+}
+
+
+static void remove_user(char *user)
+{
+ char *start_user= user;
+ while (*user != ',')
+ {
+ if (*user == 0)
+ {
+ *start_user= 0;
+ return;
+ }
+ user++;
+ }
+ user++;
+ while (*user == ' ')
+ user++;
+
+ do {
+ *(start_user++)= *user;
+ } while (*(user++));
+}
+
+
+static void remove_blanks(char *user)
+{
+ char *user_orig= user;
+ char *user_to= user;
+ char *start_tok;
+ int blank_name;
+
+ while (*user != 0)
+ {
+ start_tok= user;
+ blank_name= 1;
+ while (*user !=0 && *user != ',')
+ {
+ if (*user != ' ')
+ blank_name= 0;
+ user++;
+ }
+ if (!blank_name)
+ {
+ while (start_tok <= user)
+ *(user_to++)= *(start_tok++);
+ }
+ if (*user == ',')
+ user++;
+ }
+ if (user_to > user_orig && user_to[-1] == ',')
+ user_to--;
+ *user_to= 0;
+}
+
+
+struct user_name
+{
+ size_t name_len;
+ char *name;
+};
+
+
+struct user_coll
+{
+ int n_users;
+ struct user_name *users;
+ int n_alloced;
+};
+
+
+static void coll_init(struct user_coll *c)
+{
+ c->n_users= 0;
+ c->users= 0;
+ c->n_alloced= 0;
+}
+
+
+static void coll_free(struct user_coll *c)
+{
+ if (c->users)
+ {
+ free(c->users);
+ coll_init(c);
+ }
+}
+
+
+static int cmp_users(const void *ia, const void *ib)
+{
+ const struct user_name *a= (const struct user_name *) ia;
+ const struct user_name *b= (const struct user_name *) ib;
+ int dl= (int)(a->name_len - b->name_len);
+ if (dl != 0)
+ return dl;
+
+ return strncmp(a->name, b->name, a->name_len);
+}
+
+
+static char *coll_search(struct user_coll *c, const char *n, size_t len)
+{
+ struct user_name un;
+ struct user_name *found;
+ if (!c->n_users)
+ return 0;
+ un.name_len= len;
+ un.name= (char *) n;
+ found= (struct user_name*) bsearch(&un, c->users, c->n_users,
+ sizeof(c->users[0]), cmp_users);
+ return found ? found->name : 0;
+}
+
+
+static int coll_insert(struct user_coll *c, char *n, size_t len)
+{
+ if (c->n_users >= c->n_alloced)
+ {
+ c->n_alloced+= 128;
+ if (c->users == NULL)
+ c->users= malloc(c->n_alloced * sizeof(c->users[0]));
+ else
+ c->users= realloc(c->users, c->n_alloced * sizeof(c->users[0]));
+
+ if (c->users == NULL)
+ return 1;
+ }
+ c->users[c->n_users].name= n;
+ c->users[c->n_users].name_len= len;
+ c->n_users++;
+ return 0;
+}
+
+
+static void coll_sort(struct user_coll *c)
+{
+ if (c->n_users)
+ qsort(c->users, c->n_users, sizeof(c->users[0]), cmp_users);
+}
+
+
+static int user_coll_fill(struct user_coll *c, char *users,
+ struct user_coll *cmp_c, int take_over_cmp)
+{
+ char *orig_users= users;
+ char *cmp_user= 0;
+ size_t cmp_length;
+ int refill_cmp_coll= 0;
+
+ c->n_users= 0;
+
+ while (*users)
+ {
+ while (*users == ' ')
+ users++;
+ if (!*users)
+ return 0;
+
+ (void) getkey_user(users, &cmp_length, FALSE);
+ if (cmp_c)
+ {
+ cmp_user= coll_search(cmp_c, users, cmp_length);
+
+ if (cmp_user && take_over_cmp)
+ {
+ ADD_ATOMIC(internal_stop_logging, 1);
+ CLIENT_ERROR(1, "User '%.*b' was removed from the"
+ " server_audit_excl_users.",
+ MYF(ME_WARNING), (int) cmp_length, users);
+ ADD_ATOMIC(internal_stop_logging, -1);
+ blank_user(cmp_user);
+ refill_cmp_coll= 1;
+ }
+ else if (cmp_user)
+ {
+ ADD_ATOMIC(internal_stop_logging, 1);
+ CLIENT_ERROR(1, "User '%.*b' is in the server_audit_incl_users, "
+ "so wasn't added.", MYF(ME_WARNING), (int) cmp_length, users);
+ ADD_ATOMIC(internal_stop_logging, -1);
+ remove_user(users);
+ continue;
+ }
+ }
+ if (coll_insert(c, users, cmp_length))
+ return 1;
+ while (*users && *users != ',')
+ users++;
+ if (!*users)
+ break;
+ users++;
+ }
+
+ if (refill_cmp_coll)
+ {
+ remove_blanks(excl_users);
+ return user_coll_fill(cmp_c, excl_users, 0, 0);
+ }
+
+ if (users > orig_users && users[-1] == ',')
+ users[-1]= 0;
+
+ coll_sort(c);
+
+ return 0;
+}
+
+
+enum sa_keywords
+{
+ SQLCOM_NOTHING=0,
+ SQLCOM_DDL,
+ SQLCOM_DML,
+ SQLCOM_GRANT,
+ SQLCOM_CREATE_USER,
+ SQLCOM_ALTER_USER,
+ SQLCOM_CHANGE_MASTER,
+ SQLCOM_CREATE_SERVER,
+ SQLCOM_SET_OPTION,
+ SQLCOM_ALTER_SERVER,
+ SQLCOM_TRUNCATE,
+ SQLCOM_QUERY_ADMIN,
+ SQLCOM_DCL,
+};
+
+struct sa_keyword
+{
+ int length;
+ const char *wd;
+ struct sa_keyword *next;
+ enum sa_keywords type;
+};
+
+
+struct sa_keyword xml_word= {3, "XML", 0, SQLCOM_NOTHING};
+struct sa_keyword user_word= {4, "USER", 0, SQLCOM_NOTHING};
+struct sa_keyword data_word= {4, "DATA", 0, SQLCOM_NOTHING};
+struct sa_keyword server_word= {6, "SERVER", 0, SQLCOM_NOTHING};
+struct sa_keyword master_word= {6, "MASTER", 0, SQLCOM_NOTHING};
+struct sa_keyword password_word= {8, "PASSWORD", 0, SQLCOM_NOTHING};
+struct sa_keyword function_word= {8, "FUNCTION", 0, SQLCOM_NOTHING};
+struct sa_keyword statement_word= {9, "STATEMENT", 0, SQLCOM_NOTHING};
+struct sa_keyword procedure_word= {9, "PROCEDURE", 0, SQLCOM_NOTHING};
+
+
+struct sa_keyword keywords_to_skip[]=
+{
+ {3, "SET", &statement_word, SQLCOM_QUERY_ADMIN},
+ {0, NULL, 0, SQLCOM_DDL}
+};
+
+
+struct sa_keyword not_ddl_keywords[]=
+{
+ {4, "DROP", &user_word, SQLCOM_DCL},
+ {6, "CREATE", &user_word, SQLCOM_DCL},
+ {6, "RENAME", &user_word, SQLCOM_DCL},
+ {0, NULL, 0, SQLCOM_DDL}
+};
+
+
+struct sa_keyword ddl_keywords[]=
+{
+ {4, "DROP", 0, SQLCOM_DDL},
+ {5, "ALTER", 0, SQLCOM_DDL},
+ {6, "CREATE", 0, SQLCOM_DDL},
+ {6, "RENAME", 0, SQLCOM_DDL},
+ {8, "TRUNCATE", 0, SQLCOM_DDL},
+ {0, NULL, 0, SQLCOM_DDL}
+};
+
+
+struct sa_keyword dml_keywords[]=
+{
+ {2, "DO", 0, SQLCOM_DML},
+ {4, "CALL", 0, SQLCOM_DML},
+ {4, "LOAD", &data_word, SQLCOM_DML},
+ {4, "LOAD", &xml_word, SQLCOM_DML},
+ {6, "DELETE", 0, SQLCOM_DML},
+ {6, "INSERT", 0, SQLCOM_DML},
+ {6, "SELECT", 0, SQLCOM_DML},
+ {6, "UPDATE", 0, SQLCOM_DML},
+ {7, "HANDLER", 0, SQLCOM_DML},
+ {7, "REPLACE", 0, SQLCOM_DML},
+ {0, NULL, 0, SQLCOM_DML}
+};
+
+
+struct sa_keyword dml_no_select_keywords[]=
+{
+ {2, "DO", 0, SQLCOM_DML},
+ {4, "CALL", 0, SQLCOM_DML},
+ {4, "LOAD", &data_word, SQLCOM_DML},
+ {4, "LOAD", &xml_word, SQLCOM_DML},
+ {6, "DELETE", 0, SQLCOM_DML},
+ {6, "INSERT", 0, SQLCOM_DML},
+ {6, "UPDATE", 0, SQLCOM_DML},
+ {7, "HANDLER", 0, SQLCOM_DML},
+ {7, "REPLACE", 0, SQLCOM_DML},
+ {0, NULL, 0, SQLCOM_DML}
+};
+
+
+struct sa_keyword dcl_keywords[]=
+{
+ {6, "CREATE", &user_word, SQLCOM_DCL},
+ {4, "DROP", &user_word, SQLCOM_DCL},
+ {6, "RENAME", &user_word, SQLCOM_DCL},
+ {5, "GRANT", 0, SQLCOM_DCL},
+ {6, "REVOKE", 0, SQLCOM_DCL},
+ {3, "SET", &password_word, SQLCOM_DCL},
+ {0, NULL, 0, SQLCOM_DDL}
+};
+
+
+struct sa_keyword passwd_keywords[]=
+{
+ {3, "SET", &password_word, SQLCOM_SET_OPTION},
+ {5, "ALTER", &server_word, SQLCOM_ALTER_SERVER},
+ {5, "ALTER", &user_word, SQLCOM_ALTER_USER},
+ {5, "GRANT", 0, SQLCOM_GRANT},
+ {6, "CREATE", &user_word, SQLCOM_CREATE_USER},
+ {6, "CREATE", &server_word, SQLCOM_CREATE_SERVER},
+ {6, "CHANGE", &master_word, SQLCOM_CHANGE_MASTER},
+ {0, NULL, 0, SQLCOM_NOTHING}
+};
+
+#define MAX_KEYWORD 9
+
+
+static void error_header()
+{
+ struct tm tm_time;
+ time_t curtime;
+
+ (void) time(&curtime);
+ (void) localtime_r(&curtime, &tm_time);
+
+ (void) fprintf(stderr,"%02d%02d%02d %2d:%02d:%02d server_audit: ",
+ tm_time.tm_year % 100, tm_time.tm_mon + 1,
+ tm_time.tm_mday, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec);
+}
+
+
+static LOGGER_HANDLE *logfile;
+static struct user_coll incl_user_coll, excl_user_coll;
+static unsigned long long query_counter= 1;
+
+
+static struct connection_info *get_loc_info(MYSQL_THD thd)
+{
+ return (struct connection_info *) THDVAR(thd, loc_info);
+}
+
+
+static int ci_needs_setup(const struct connection_info *ci)
+{
+ return ci->header != 0;
+}
+
+
+static void get_str_n(char *dest, int *dest_len, size_t dest_size,
+ const char *src, size_t src_len)
+{
+ if (src_len >= dest_size)
+ src_len= dest_size - 1;
+
+ if (src_len)
+ memcpy(dest, src, src_len);
+ dest[src_len]= 0;
+ *dest_len= (int)src_len;
+}
+
+
+static int get_user_host(const char *uh_line, unsigned int uh_len,
+ char *buffer, size_t buf_len,
+ size_t *user_len, size_t *host_len, size_t *ip_len)
+{
+ const char *buf_end= buffer + buf_len - 1;
+ const char *buf_start;
+ const char *uh_end= uh_line + uh_len;
+
+ while (uh_line < uh_end && *uh_line != '[')
+ ++uh_line;
+
+ if (uh_line == uh_end)
+ return 1;
+ ++uh_line;
+
+ buf_start= buffer;
+ while (uh_line < uh_end && *uh_line != ']')
+ {
+ if (buffer == buf_end)
+ return 1;
+ *(buffer++)= *(uh_line++);
+ }
+ if (uh_line == uh_end)
+ return 1;
+ *user_len= buffer - buf_start;
+ *(buffer++)= 0;
+
+ while (uh_line < uh_end && *uh_line != '@')
+ ++uh_line;
+ if (uh_line == uh_end || *(++uh_line) == 0)
+ return 1;
+ ++uh_line;
+
+ buf_start= buffer;
+ while (uh_line < uh_end && *uh_line != ' ' && *uh_line != '[')
+ {
+ if (buffer == buf_end)
+ break;
+ *(buffer++)= *(uh_line++);
+ }
+ *host_len= buffer - buf_start;
+ *(buffer++)= 0;
+
+ while (uh_line < uh_end && *uh_line != '[')
+ ++uh_line;
+
+ buf_start= buffer;
+ if (*uh_line == '[')
+ {
+ ++uh_line;
+ while (uh_line < uh_end && *uh_line != ']')
+ *(buffer++)= *(uh_line++);
+ }
+ *ip_len= buffer - buf_start;
+ return 0;
+}
+
+#if defined(__WIN__) && !defined(S_ISDIR)
+#define S_ISDIR(x) ((x) & _S_IFDIR)
+#endif /*__WIN__ && !S_ISDIR*/
+
+static int start_logging()
+{
+ last_error_buf[0]= 0;
+ log_write_failures= 0;
+ if (output_type == OUTPUT_FILE)
+ {
+ char alt_path_buffer[FN_REFLEN+1+DEFAULT_FILENAME_LEN];
+ struct stat *f_stat= (struct stat *)alt_path_buffer;
+ const char *alt_fname= file_path;
+
+ while (*alt_fname == ' ')
+ alt_fname++;
+
+ if (*alt_fname == 0)
+ {
+ /* Empty string means the default file name. */
+ alt_fname= default_file_name;
+ }
+ else
+ {
+ /* See if the directory exists with the name of file_path. */
+ /* Log file name should be [file_path]/server_audit.log then. */
+ if (stat(file_path, (struct stat *)alt_path_buffer) == 0 &&
+ S_ISDIR(f_stat->st_mode))
+ {
+ size_t p_len= strlen(file_path);
+ memcpy(alt_path_buffer, file_path, p_len);
+ if (alt_path_buffer[p_len-1] != FN_LIBCHAR)
+ {
+ alt_path_buffer[p_len]= FN_LIBCHAR;
+ p_len++;
+ }
+ memcpy(alt_path_buffer+p_len, default_file_name, DEFAULT_FILENAME_LEN);
+ alt_path_buffer[p_len+DEFAULT_FILENAME_LEN]= 0;
+ alt_fname= alt_path_buffer;
+ }
+ }
+
+ logfile= logger_open(alt_fname, file_rotate_size, rotations);
+
+ if (logfile == NULL)
+ {
+ error_header();
+ fprintf(stderr, "Could not create file '%s'.\n",
+ alt_fname);
+ logging= 0;
+ my_snprintf(last_error_buf, sizeof(last_error_buf),
+ "Could not create file '%s'.", alt_fname);
+ is_active= 0;
+ CLIENT_ERROR(1, "SERVER AUDIT plugin can't create file '%s'.",
+ MYF(ME_WARNING), alt_fname);
+ return 1;
+ }
+ error_header();
+ fprintf(stderr, "logging started to the file %s.\n", alt_fname);
+ strncpy(current_log_buf, alt_fname, sizeof(current_log_buf)-1);
+ current_log_buf[sizeof(current_log_buf)-1]= 0;
+ }
+ else if (output_type == OUTPUT_SYSLOG)
+ {
+ openlog(syslog_ident, LOG_NOWAIT, syslog_facility_codes[syslog_facility]);
+ error_header();
+ fprintf(stderr, "logging started to the syslog.\n");
+ strncpy(current_log_buf, "[SYSLOG]", sizeof(current_log_buf)-1);
+ compile_time_assert(sizeof current_log_buf > sizeof "[SYSLOG]");
+ }
+ is_active= 1;
+ return 0;
+}
+
+
+static int stop_logging()
+{
+ last_error_buf[0]= 0;
+ if (output_type == OUTPUT_FILE && logfile)
+ {
+ logger_close(logfile);
+ logfile= NULL;
+ }
+ else if (output_type == OUTPUT_SYSLOG)
+ {
+ closelog();
+ }
+ error_header();
+ fprintf(stderr, "logging was stopped.\n");
+ is_active= 0;
+ return 0;
+}
+
+
+static void setup_connection_simple(struct connection_info *ci)
+{
+ ci->db_length= 0;
+ ci->user_length= 0;
+ ci->host_length= 0;
+ ci->ip_length= 0;
+ ci->query_length= 0;
+ ci->header= 0;
+ ci->proxy_length= 0;
+}
+
+
+#define MAX_HOSTNAME 61
+#define USERNAME_LENGTH 384
+
+static void setup_connection_connect(struct connection_info *cn,
+ const struct mysql_event_connection *event)
+{
+ cn->query_id= 0;
+ cn->query_length= 0;
+ cn->log_always= 0;
+ cn->thread_id= event->thread_id;
+ get_str_n(cn->db, &cn->db_length, sizeof(cn->db),
+ event->database.str, event->database.length);
+ get_str_n(cn->user, &cn->user_length, sizeof(cn->db),
+ event->user, event->user_length);
+ get_str_n(cn->host, &cn->host_length, sizeof(cn->host),
+ event->host, event->host_length);
+ get_str_n(cn->ip, &cn->ip_length, sizeof(cn->ip),
+ event->ip, event->ip_length);
+ cn->header= 0;
+ if (event->proxy_user && event->proxy_user[0])
+ {
+ const char *priv_host= event->proxy_user +
+ sizeof(char[MAX_HOSTNAME+USERNAME_LENGTH+5]);
+ size_t priv_host_length;
+
+ if (mysql_57_started)
+ {
+ priv_host+= sizeof(size_t);
+ priv_host_length= *(size_t *) (priv_host + MAX_HOSTNAME);
+ }
+ else
+ priv_host_length= strlen(priv_host);
+
+
+ get_str_n(cn->proxy, &cn->proxy_length, sizeof(cn->proxy),
+ event->priv_user, event->priv_user_length);
+ get_str_n(cn->proxy_host, &cn->proxy_host_length,
+ sizeof(cn->proxy_host),
+ priv_host, priv_host_length);
+ }
+ else
+ cn->proxy_length= 0;
+}
+
+
+#define SAFE_STRLEN(s) (s ? strlen(s) : 0)
+#define SAFE_STRLEN_UI(s) ((unsigned int) (s ? strlen(s) : 0))
+static char empty_str[1]= { 0 };
+
+
+static int is_space(char c)
+{
+ return c == ' ' || c == '\r' || c == '\n' || c == '\t';
+}
+
+
+#define SKIP_SPACES(str) \
+do { \
+ while (is_space(*str)) \
+ ++str; \
+} while(0)
+
+
+#define ESC_MAP_SIZE 0x60
+static const char esc_map[ESC_MAP_SIZE]=
+{
+ 0, 0, 0, 0, 0, 0, 0, 0, 'b', 't', 'n', 0, 'f', 'r', 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, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0
+};
+
+static char escaped_char(char c)
+{
+ return ((unsigned char ) c) >= ESC_MAP_SIZE ? 0 : esc_map[(unsigned char) c];
+}
+
+
+static void setup_connection_initdb(struct connection_info *cn,
+ const struct mysql_event_general *event)
+{
+ size_t user_len, host_len, ip_len;
+ char uh_buffer[512];
+
+ cn->thread_id= event->general_thread_id;
+ cn->query_id= 0;
+ cn->query_length= 0;
+ cn->log_always= 0;
+ get_str_n(cn->db, &cn->db_length, sizeof(cn->db),
+ event->general_query, event->general_query_length);
+
+ if (get_user_host(event->general_user, event->general_user_length,
+ uh_buffer, sizeof(uh_buffer),
+ &user_len, &host_len, &ip_len))
+ {
+ /* The user@host line is incorrect. */
+ cn->user_length= 0;
+ cn->host_length= 0;
+ cn->ip_length= 0;
+ }
+ else
+ {
+ get_str_n(cn->user, &cn->user_length, sizeof(cn->user),
+ uh_buffer, user_len);
+ get_str_n(cn->host, &cn->host_length, sizeof(cn->host),
+ uh_buffer+user_len+1, host_len);
+ get_str_n(cn->ip, &cn->ip_length, sizeof(cn->ip),
+ uh_buffer+user_len+1+host_len+1, ip_len);
+ }
+ cn->header= 0;
+}
+
+
+static void setup_connection_table(struct connection_info *cn,
+ const struct mysql_event_table *event)
+{
+ cn->thread_id= event->thread_id;
+ cn->query_id= query_counter++;
+ cn->log_always= 0;
+ cn->query_length= 0;
+ get_str_n(cn->db, &cn->db_length, sizeof(cn->db),
+ event->database.str, event->database.length);
+ get_str_n(cn->user, &cn->user_length, sizeof(cn->db),
+ event->user, SAFE_STRLEN(event->user));
+ get_str_n(cn->host, &cn->host_length, sizeof(cn->host),
+ event->host, SAFE_STRLEN(event->host));
+ get_str_n(cn->ip, &cn->ip_length, sizeof(cn->ip),
+ event->ip, SAFE_STRLEN(event->ip));
+ cn->header= 0;
+}
+
+
+static void setup_connection_query(struct connection_info *cn,
+ const struct mysql_event_general *event)
+{
+ size_t user_len, host_len, ip_len;
+ char uh_buffer[512];
+
+ cn->thread_id= event->general_thread_id;
+ cn->query_id= query_counter++;
+ cn->log_always= 0;
+ cn->query_length= 0;
+ get_str_n(cn->db, &cn->db_length, sizeof(cn->db), "", 0);
+
+ if (get_user_host(event->general_user, event->general_user_length,
+ uh_buffer, sizeof(uh_buffer),
+ &user_len, &host_len, &ip_len))
+ {
+ /* The user@host line is incorrect. */
+ cn->user_length= 0;
+ cn->host_length= 0;
+ cn->ip_length= 0;
+ }
+ else
+ {
+ get_str_n(cn->user, &cn->user_length, sizeof(cn->user),
+ uh_buffer, user_len);
+ get_str_n(cn->host, &cn->host_length, sizeof(cn->host),
+ uh_buffer+user_len+1, host_len);
+ get_str_n(cn->ip, &cn->ip_length, sizeof(cn->ip),
+ uh_buffer+user_len+1+host_len+1, ip_len);
+ }
+ cn->header= 0;
+}
+
+
+static void change_connection(struct connection_info *cn,
+ const struct mysql_event_connection *event)
+{
+ get_str_n(cn->user, &cn->user_length, sizeof(cn->user),
+ event->user, event->user_length);
+ get_str_n(cn->ip, &cn->ip_length, sizeof(cn->ip),
+ event->ip, event->ip_length);
+}
+
+/*
+ Write to the log
+
+ @param take_lock If set, take a read lock (or write lock on rotate).
+ If not set, the caller has a already taken a write lock
+*/
+
+static int write_log(const char *message, size_t len, int take_lock)
+{
+ int result= 0;
+ if (take_lock)
+ {
+ /* Start by taking a read lock */
+ mysql_prlock_rdlock(&lock_operations);
+ }
+
+ if (output_type == OUTPUT_FILE)
+ {
+ if (logfile)
+ {
+ my_bool allow_rotate= !take_lock; /* Allow rotate if caller write lock */
+ if (take_lock && logger_time_to_rotate(logfile))
+ {
+ /* We have to rotate the log, change above read lock to write lock */
+ mysql_prlock_unlock(&lock_operations);
+ mysql_prlock_wrlock(&lock_operations);
+ allow_rotate= 1;
+ }
+ if (!(is_active= (logger_write_r(logfile, allow_rotate, message, len) ==
+ (int) len)))
+ {
+ ++log_write_failures;
+ result= 1;
+ }
+ }
+ }
+ else if (output_type == OUTPUT_SYSLOG)
+ {
+ syslog(syslog_facility_codes[syslog_facility] |
+ syslog_priority_codes[syslog_priority],
+ "%s %.*s", syslog_info, (int) len, message);
+ }
+ if (take_lock)
+ mysql_prlock_unlock(&lock_operations);
+ return result;
+}
+
+
+static size_t log_header(char *message, size_t message_len,
+ time_t *ts,
+ const char *serverhost, size_t serverhost_len,
+ const char *username, unsigned int username_len,
+ const char *host, unsigned int host_len,
+ const char *userip, unsigned int userip_len,
+ unsigned int connection_id, long long query_id,
+ const char *operation)
+{
+ struct tm tm_time;
+
+ if (host_len == 0 && userip_len != 0)
+ {
+ host_len= userip_len;
+ host= userip;
+ }
+
+ if (output_type == OUTPUT_SYSLOG)
+ return my_snprintf(message, message_len,
+ "%.*s,%.*s,%.*s,%d,%lld,%s",
+ (unsigned int) serverhost_len, serverhost,
+ username_len, username,
+ host_len, host,
+ connection_id, query_id, operation);
+
+ (void) localtime_r(ts, &tm_time);
+ return my_snprintf(message, message_len,
+ "%04d%02d%02d %02d:%02d:%02d,%.*s,%.*s,%.*s,%d,%lld,%s",
+ tm_time.tm_year+1900, tm_time.tm_mon+1, tm_time.tm_mday,
+ tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec,
+ serverhost_len, serverhost,
+ username_len, username,
+ host_len, host,
+ connection_id, query_id, operation);
+}
+
+
+static int log_proxy(const struct connection_info *cn,
+ const struct mysql_event_connection *event)
+
+{
+ time_t ctime;
+ size_t csize;
+ char message[1024];
+
+ (void) time(&ctime);
+ csize= log_header(message, sizeof(message)-1, &ctime,
+ servhost, servhost_len,
+ cn->user, cn->user_length,
+ cn->host, cn->host_length,
+ cn->ip, cn->ip_length,
+ event->thread_id, 0, "PROXY_CONNECT");
+ csize+= my_snprintf(message+csize, sizeof(message) - 1 - csize,
+ ",%.*s,`%.*s`@`%.*s`,%d", cn->db_length, cn->db,
+ cn->proxy_length, cn->proxy,
+ cn->proxy_host_length, cn->proxy_host,
+ event->status);
+ message[csize]= '\n';
+ return write_log(message, csize + 1, 1);
+}
+
+
+static int log_connection(const struct connection_info *cn,
+ const struct mysql_event_connection *event,
+ const char *type)
+{
+ time_t ctime;
+ size_t csize;
+ char message[1024];
+
+ (void) time(&ctime);
+ csize= log_header(message, sizeof(message)-1, &ctime,
+ servhost, servhost_len,
+ cn->user, cn->user_length,
+ cn->host, cn->host_length,
+ cn->ip, cn->ip_length,
+ event->thread_id, 0, type);
+ csize+= my_snprintf(message+csize, sizeof(message) - 1 - csize,
+ ",%.*s,,%d", cn->db_length, cn->db, event->status);
+ message[csize]= '\n';
+ return write_log(message, csize + 1, 1);
+}
+
+
+static int log_connection_event(const struct mysql_event_connection *event,
+ const char *type)
+{
+ time_t ctime;
+ size_t csize;
+ char message[1024];
+
+ (void) time(&ctime);
+ csize= log_header(message, sizeof(message)-1, &ctime,
+ servhost, servhost_len,
+ event->user, event->user_length,
+ event->host, event->host_length,
+ event->ip, event->ip_length,
+ event->thread_id, 0, type);
+ csize+= my_snprintf(message+csize, sizeof(message) - 1 - csize,
+ ",%.*s,,%d", event->database.length, event->database.str, event->status);
+ message[csize]= '\n';
+ return write_log(message, csize + 1, 1);
+}
+
+
+static size_t escape_string(const char *str, unsigned int len,
+ char *result, size_t result_len)
+{
+ const char *res_start= result;
+ const char *res_end= result + result_len - 2;
+ while (len)
+ {
+ char esc_c;
+
+ if (result >= res_end)
+ break;
+ if ((esc_c= escaped_char(*str)))
+ {
+ if (result+1 >= res_end)
+ break;
+ *(result++)= '\\';
+ *(result++)= esc_c;
+ }
+ else if (is_space(*str))
+ *(result++)= ' ';
+ else
+ *(result++)= *str;
+ str++;
+ len--;
+ }
+ *result= 0;
+ return result - res_start;
+}
+
+
+static size_t escape_string_hide_passwords(const char *str, unsigned int len,
+ char *result, size_t result_len,
+ const char *word1, size_t word1_len,
+ const char *word2, size_t word2_len,
+ int next_text_string)
+{
+ const char *res_start= result;
+ const char *res_end= result + result_len - 2;
+ size_t d_len;
+
+ while (len)
+ {
+ if (len > word1_len + 1 && strncasecmp(str, word1, word1_len) == 0)
+ {
+ const char *next_s= str + word1_len;
+ size_t c;
+
+ if (next_text_string)
+ {
+ while (*next_s && *next_s != '\'' && *next_s != '"')
+ ++next_s;
+ }
+ else
+ {
+ if (word2)
+ {
+ SKIP_SPACES(next_s);
+ if (len < (next_s - str) + word2_len + 1 ||
+ strncasecmp(next_s, word2, word2_len) != 0)
+ goto no_password;
+ next_s+= word2_len;
+ }
+
+ while (*next_s && *next_s != '\'' && *next_s != '"')
+ ++next_s;
+ }
+
+ d_len= next_s - str;
+ if (result + d_len + 5 > res_end)
+ break;
+
+ for (c=0; c<d_len; c++)
+ result[c]= is_space(str[c]) ? ' ' : str[c];
+
+ if (*next_s)
+ {
+ const char b_char= *next_s++;
+ memset(result + d_len, '*', 5);
+ result+= d_len + 5;
+
+ while (*next_s)
+ {
+ if (*next_s == b_char)
+ {
+ ++next_s;
+ break;
+ }
+ if (*next_s == '\\')
+ {
+ if (next_s[1])
+ next_s++;
+ }
+ next_s++;
+ }
+ }
+ else
+ result+= d_len;
+
+ len-= (uint)(next_s - str);
+ str= next_s;
+ continue;
+ }
+no_password:
+ if (result >= res_end)
+ break;
+ else
+ {
+ const char b_char= escaped_char(*str);
+ if (b_char)
+ {
+ if (result+1 >= res_end)
+ break;
+ *(result++)= '\\';
+ *(result++)= b_char;
+ }
+ else if (is_space(*str))
+ *(result++)= ' ';
+ else
+ *(result++)= *str;
+ str++;
+ len--;
+ }
+ }
+ *result= 0;
+ return result - res_start;
+}
+
+
+
+static int do_log_user(const char *name, int len,
+ const char *proxy, int proxy_len, int take_lock)
+{
+ int result;
+
+ if (!name)
+ return 0;
+
+ if (take_lock)
+ mysql_prlock_rdlock(&lock_operations);
+
+ if (incl_user_coll.n_users)
+ {
+ result= coll_search(&incl_user_coll, name, len) != 0 ||
+ (proxy && coll_search(&incl_user_coll, proxy, proxy_len) != 0);
+ }
+ else if (excl_user_coll.n_users)
+ {
+ result= coll_search(&excl_user_coll, name, len) == 0 &&
+ (proxy && coll_search(&excl_user_coll, proxy, proxy_len) == 0);
+ }
+ else
+ result= 1;
+
+ if (take_lock)
+ mysql_prlock_unlock(&lock_operations);
+ return result;
+}
+
+
+static int get_next_word(const char *query, char *word)
+{
+ int len= 0;
+ char c;
+ while ((c= query[len]))
+ {
+ if (c >= 'a' && c <= 'z')
+ word[len]= 'A' + (c-'a');
+ else if (c >= 'A' && c <= 'Z')
+ word[len]= c;
+ else
+ break;
+
+ if (len++ == MAX_KEYWORD)
+ return 0;
+ }
+ word[len]= 0;
+ return len;
+}
+
+
+static int filter_query_type(const char *query, struct sa_keyword *kwd)
+{
+ int qwe_in_list;
+ char fword[MAX_KEYWORD + 1], nword[MAX_KEYWORD + 1];
+ int len, nlen= 0;
+ const struct sa_keyword *l_keywords;
+
+ while (*query && (is_space(*query) || *query == '(' || *query == '/'))
+ {
+ /* comment handling */
+ if (*query == '/' && query[1] == '*')
+ {
+ if (query[2] == '!')
+ {
+ query+= 3;
+ while (*query >= '0' && *query <= '9')
+ query++;
+ continue;
+ }
+ query+= 2;
+ while (*query)
+ {
+ if (*query=='*' && query[1] == '/')
+ {
+ query+= 2;
+ break;
+ }
+ query++;
+ }
+ continue;
+ }
+ query++;
+ }
+
+ qwe_in_list= 0;
+ if (!(len= get_next_word(query, fword)))
+ goto not_in_list;
+ query+= len+1;
+
+ l_keywords= kwd;
+ while (l_keywords->length)
+ {
+ if (l_keywords->length == len && strncmp(l_keywords->wd, fword, len) == 0)
+ {
+ if (l_keywords->next)
+ {
+ if (nlen == 0)
+ {
+ while (*query && is_space(*query))
+ query++;
+ nlen= get_next_word(query, nword);
+ }
+ if (l_keywords->next->length != nlen ||
+ strncmp(l_keywords->next->wd, nword, nlen) != 0)
+ goto do_loop;
+ }
+
+ qwe_in_list= l_keywords->type;
+ break;
+ };
+do_loop:
+ l_keywords++;
+ }
+
+not_in_list:
+ return qwe_in_list;
+}
+
+
+static int log_statement_ex(const struct connection_info *cn,
+ time_t ev_time, unsigned long thd_id,
+ const char *query, unsigned int query_len,
+ int error_code, const char *type, int take_lock)
+{
+ size_t csize;
+ char message_loc[1024];
+ char *message= message_loc;
+ size_t message_size= sizeof(message_loc);
+ char *uh_buffer;
+ size_t uh_buffer_size;
+ const char *db;
+ unsigned int db_length;
+ long long query_id;
+ int result;
+
+ if ((db= cn->db))
+ db_length= cn->db_length;
+ else
+ {
+ db= "";
+ db_length= 0;
+ }
+
+ if (!(query_id= cn->query_id))
+ query_id= query_counter++;
+
+ if (query == 0)
+ {
+ /* Can happen after the error in mysqld_prepare_stmt() */
+ query= cn->query;
+ query_len= cn->query_length;
+ if (query == 0 || query_len == 0)
+ return 0;
+ }
+
+ if (query && !(events & EVENT_QUERY_ALL) &&
+ (events & EVENT_QUERY && !cn->log_always))
+ {
+ const char *orig_query= query;
+
+ if (filter_query_type(query, keywords_to_skip))
+ {
+ char fword[MAX_KEYWORD + 1];
+ int len;
+ do
+ {
+ len= get_next_word(query, fword);
+ query+= len ? len : 1;
+ if (len == 3 && strncmp(fword, "FOR", 3) == 0)
+ break;
+ } while (*query);
+
+ if (*query == 0)
+ return 0;
+ }
+
+ if (events & EVENT_QUERY_DDL)
+ {
+ if (!filter_query_type(query, not_ddl_keywords) &&
+ filter_query_type(query, ddl_keywords))
+ goto do_log_query;
+ }
+ if (events & EVENT_QUERY_DML)
+ {
+ if (filter_query_type(query, dml_keywords))
+ goto do_log_query;
+ }
+ if (events & EVENT_QUERY_DML_NO_SELECT)
+ {
+ if (filter_query_type(query, dml_no_select_keywords))
+ goto do_log_query;
+ }
+ if (events & EVENT_QUERY_DCL)
+ {
+ if (filter_query_type(query, dcl_keywords))
+ goto do_log_query;
+ }
+
+ return 0;
+do_log_query:
+ query= orig_query;
+ }
+
+ csize= log_header(message, message_size-1, &ev_time,
+ servhost, servhost_len,
+ cn->user, cn->user_length,cn->host, cn->host_length,
+ cn->ip, cn->ip_length, thd_id, query_id, type);
+
+ csize+= my_snprintf(message+csize, message_size - 1 - csize,
+ ",%.*s,\'", db_length, db);
+
+ if (query_log_limit > 0 && query_len > query_log_limit)
+ query_len= query_log_limit;
+
+ if (query_len > (message_size - csize)/2)
+ {
+ flogger_mutex_lock(&lock_bigbuffer);
+ if (big_buffer_alloced < (query_len * 2 + csize))
+ {
+ big_buffer_alloced= (query_len * 2 + csize + 4095) & ~4095L;
+ big_buffer= realloc(big_buffer, big_buffer_alloced);
+ if (big_buffer == NULL)
+ {
+ big_buffer_alloced= 0;
+ return 0;
+ }
+ }
+
+ memcpy(big_buffer, message, csize);
+ message= big_buffer;
+ message_size= big_buffer_alloced;
+ }
+
+ uh_buffer= message + csize;
+ uh_buffer_size= message_size - csize;
+ if (query_log_limit > 0 && uh_buffer_size > query_log_limit+2)
+ uh_buffer_size= query_log_limit+2;
+
+ switch (filter_query_type(query, passwd_keywords))
+ {
+ case SQLCOM_GRANT:
+ case SQLCOM_CREATE_USER:
+ case SQLCOM_ALTER_USER:
+ csize+= escape_string_hide_passwords(query, query_len,
+ uh_buffer, uh_buffer_size,
+ "IDENTIFIED", 10, "BY", 2, 0);
+ break;
+ case SQLCOM_CHANGE_MASTER:
+ csize+= escape_string_hide_passwords(query, query_len,
+ uh_buffer, uh_buffer_size,
+ "MASTER_PASSWORD", 15, "=", 1, 0);
+ break;
+ case SQLCOM_CREATE_SERVER:
+ case SQLCOM_ALTER_SERVER:
+ csize+= escape_string_hide_passwords(query, query_len,
+ uh_buffer, uh_buffer_size,
+ "PASSWORD", 8, NULL, 0, 0);
+ break;
+ case SQLCOM_SET_OPTION:
+ csize+= escape_string_hide_passwords(query, query_len,
+ uh_buffer, uh_buffer_size,
+ "=", 1, NULL, 0, 1);
+ break;
+ default:
+ csize+= escape_string(query, query_len,
+ uh_buffer, uh_buffer_size);
+ break;
+ }
+ csize+= my_snprintf(message+csize, message_size - 1 - csize,
+ "\',%d", error_code);
+ message[csize]= '\n';
+ result= write_log(message, csize + 1, take_lock);
+ if (message == big_buffer)
+ flogger_mutex_unlock(&lock_bigbuffer);
+
+ return result;
+}
+
+
+static int log_statement(const struct connection_info *cn,
+ const struct mysql_event_general *event,
+ const char *type)
+{
+ return log_statement_ex(cn, event->general_time, event->general_thread_id,
+ event->general_query, event->general_query_length,
+ event->general_error_code, type, 1);
+}
+
+
+static int log_table(const struct connection_info *cn,
+ const struct mysql_event_table *event, const char *type)
+{
+ size_t csize;
+ char message[1024];
+ time_t ctime;
+
+ (void) time(&ctime);
+ csize= log_header(message, sizeof(message)-1, &ctime,
+ servhost, servhost_len,
+ event->user, SAFE_STRLEN_UI(event->user),
+ event->host, SAFE_STRLEN_UI(event->host),
+ event->ip, SAFE_STRLEN_UI(event->ip),
+ event->thread_id, cn->query_id, type);
+ csize+= my_snprintf(message+csize, sizeof(message) - 1 - csize,
+ ",%.*s,%.*s,",event->database.length, event->database.str,
+ event->table.length, event->table.str);
+ message[csize]= '\n';
+ return write_log(message, csize + 1, 1);
+}
+
+
+static int log_rename(const struct connection_info *cn,
+ const struct mysql_event_table *event)
+{
+ size_t csize;
+ char message[1024];
+ time_t ctime;
+
+ (void) time(&ctime);
+ csize= log_header(message, sizeof(message)-1, &ctime,
+ servhost, servhost_len,
+ event->user, SAFE_STRLEN_UI(event->user),
+ event->host, SAFE_STRLEN_UI(event->host),
+ event->ip, SAFE_STRLEN_UI(event->ip),
+ event->thread_id, cn->query_id, "RENAME");
+ csize+= my_snprintf(message+csize, sizeof(message) - 1 - csize,
+ ",%.*s,%.*s|%.*s.%.*s,",event->database.length, event->database.str,
+ event->table.length, event->table.str,
+ event->new_database.length, event->new_database.str,
+ event->new_table.length, event->new_table.str);
+ message[csize]= '\n';
+ return write_log(message, csize + 1, 1);
+}
+
+
+static int event_query_command(const struct mysql_event_general *event)
+{
+ return (event->general_command_length == 5 &&
+ strncmp(event->general_command, "Query", 5) == 0) ||
+ (event->general_command_length == 7 &&
+ (strncmp(event->general_command, "Execute", 7) == 0 ||
+ (event->general_error_code != 0 &&
+ strncmp(event->general_command, "Prepare", 7) == 0)));
+}
+
+
+static void update_general_user(struct connection_info *cn,
+ const struct mysql_event_general *event)
+{
+ char uh_buffer[768];
+ size_t user_len, host_len, ip_len;
+ if (cn->user_length == 0 && cn->host_length == 0 && cn->ip_length == 0 &&
+ get_user_host(event->general_user, event->general_user_length,
+ uh_buffer, sizeof(uh_buffer),
+ &user_len, &host_len, &ip_len) == 0)
+ {
+ get_str_n(cn->user, &cn->user_length, sizeof(cn->user),
+ uh_buffer, user_len);
+ get_str_n(cn->host, &cn->host_length, sizeof(cn->host),
+ uh_buffer+user_len+1, host_len);
+ get_str_n(cn->ip, &cn->ip_length, sizeof(cn->ip),
+ uh_buffer+user_len+1+host_len+1, ip_len);
+ }
+
+}
+
+
+static struct connection_info ci_disconnect_buffer;
+
+#define AA_FREE_CONNECTION 1
+#define AA_CHANGE_USER 2
+
+static void update_connection_info(struct connection_info *cn,
+ unsigned int event_class, const void *ev, int *after_action)
+{
+ *after_action= 0;
+
+ switch (event_class) {
+ case MYSQL_AUDIT_GENERAL_CLASS:
+ {
+ const struct mysql_event_general *event =
+ (const struct mysql_event_general *) ev;
+ switch (event->event_subclass) {
+ case MYSQL_AUDIT_GENERAL_LOG:
+ {
+ int init_db_command= event->general_command_length == 7 &&
+ strncmp(event->general_command, "Init DB", 7) == 0;
+ if (!ci_needs_setup(cn))
+ {
+ if (init_db_command)
+ {
+ /* Change DB */
+ if (mysql_57_started)
+ get_str_n(cn->db, &cn->db_length, sizeof(cn->db),
+ event->database.str, event->database.length);
+ else
+ get_str_n(cn->db, &cn->db_length, sizeof(cn->db),
+ event->general_query, event->general_query_length);
+ }
+ cn->query_id= mode ? query_counter++ : event->query_id;
+ cn->query= event->general_query;
+ cn->query_length= event->general_query_length;
+ cn->query_time= (time_t) event->general_time;
+ update_general_user(cn, event);
+ }
+ else if (init_db_command)
+ setup_connection_initdb(cn, event);
+ else if (event_query_command(event))
+ setup_connection_query(cn, event);
+ else
+ setup_connection_simple(cn);
+ break;
+ }
+
+ case MYSQL_AUDIT_GENERAL_STATUS:
+ if (event_query_command(event))
+ {
+ if (ci_needs_setup(cn))
+ setup_connection_query(cn, event);
+
+ if (mode == 0 && cn->db_length == 0 && event->database.length > 0)
+ get_str_n(cn->db, &cn->db_length, sizeof(cn->db),
+ event->database.str, event->database.length);
+
+ if (event->general_error_code == 0)
+ {
+ /* We need to check if it's the USE command to change the DB */
+ int use_command= event->general_query_length > 4 &&
+ strncasecmp(event->general_query, "use ", 4) == 0;
+ if (use_command)
+ {
+ /* Change DB */
+ if (mode)
+ get_str_n(cn->db, &cn->db_length, sizeof(cn->db),
+ event->general_query + 4, event->general_query_length - 4);
+ else
+ get_str_n(cn->db, &cn->db_length, sizeof(cn->db),
+ event->database.str, event->database.length);
+ }
+ }
+ update_general_user(cn, event);
+ }
+ break;
+ case MYSQL_AUDIT_GENERAL_ERROR:
+ /*
+ We need this because the MariaDB returns NULL query field for the
+ MYSQL_AUDIT_GENERAL_STATUS in the mysqld_stmt_prepare.
+ As a result we get empty QUERY field for errors.
+ */
+ if (ci_needs_setup(cn))
+ setup_connection_query(cn, event);
+ cn->query_id= mode ? query_counter++ : event->query_id;
+ get_str_n(cn->query_buffer, &cn->query_length, sizeof(cn->query_buffer),
+ event->general_query, event->general_query_length);
+ cn->query= cn->query_buffer;
+ cn->query_time= (time_t) event->general_time;
+ break;
+ default:;
+ }
+ break;
+ }
+ case MYSQL_AUDIT_TABLE_CLASS:
+ {
+ const struct mysql_event_table *event =
+ (const struct mysql_event_table *) ev;
+ if (ci_needs_setup(cn))
+ setup_connection_table(cn, event);
+
+ if (cn->user_length == 0 && cn->host_length == 0 && cn->ip_length == 0)
+ {
+ get_str_n(cn->user, &cn->user_length, sizeof(cn->user),
+ event->user, SAFE_STRLEN(event->user));
+ get_str_n(cn->host, &cn->host_length, sizeof(cn->host),
+ event->host, SAFE_STRLEN(event->host));
+ get_str_n(cn->ip, &cn->ip_length, sizeof(cn->ip),
+ event->ip, SAFE_STRLEN(event->ip));
+ }
+
+ if (cn->db_length == 0 && event->database.length != 0)
+ get_str_n(cn->db, &cn->db_length, sizeof(cn->db),
+ event->database.str, event->database.length);
+
+ if (mode == 0)
+ cn->query_id= event->query_id;
+ break;
+ }
+ case MYSQL_AUDIT_CONNECTION_CLASS:
+ {
+ const struct mysql_event_connection *event =
+ (const struct mysql_event_connection *) ev;
+ switch (event->event_subclass)
+ {
+ case MYSQL_AUDIT_CONNECTION_CONNECT:
+ setup_connection_connect(cn, event);
+ break;
+ case MYSQL_AUDIT_CONNECTION_CHANGE_USER:
+ *after_action= AA_CHANGE_USER;
+ break;
+ default:;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+
+struct connection_info cn_error_buffer;
+
+
+#define FILTER(MASK) (events == 0 || (events & MASK))
+void auditing(MYSQL_THD thd, unsigned int event_class, const void *ev)
+{
+ struct connection_info *cn= 0;
+ int after_action= 0;
+
+ /* That one is important as this function can be called with */
+ /* &lock_operations locked when the server logs an error reported */
+ /* by this plugin. */
+ if (!thd || internal_stop_logging)
+ return;
+
+ if (maria_55_started && debug_server_started &&
+ event_class == MYSQL_AUDIT_GENERAL_CLASS)
+ {
+ /*
+ There's a bug in MariaDB 5.5 that prevents using thread local
+ variables in some cases.
+ The 'select * from notexisting_table;' query produces such case.
+ So just use the static buffer in this case.
+ */
+ const struct mysql_event_general *event =
+ (const struct mysql_event_general *) ev;
+
+ if (event->event_subclass == MYSQL_AUDIT_GENERAL_ERROR ||
+ (event->event_subclass == MYSQL_AUDIT_GENERAL_STATUS &&
+ event->general_query_length == 0 &&
+ cn_error_buffer.query_id == event->query_id))
+ {
+ cn= &cn_error_buffer;
+ cn->header= 1;
+ }
+ else
+ cn= get_loc_info(thd);
+ }
+ else
+ {
+ cn= get_loc_info(thd);
+ }
+
+ update_connection_info(cn, event_class, ev, &after_action);
+
+ if (!logging)
+ {
+ if (cn)
+ cn->log_always= 0;
+ goto exit_func;
+ }
+
+ if (event_class == MYSQL_AUDIT_GENERAL_CLASS && FILTER(EVENT_QUERY) &&
+ cn && (cn->log_always || do_log_user(cn->user, cn->user_length,
+ cn->proxy, cn->proxy_length,
+ 1)))
+ {
+ const struct mysql_event_general *event =
+ (const struct mysql_event_general *) ev;
+
+ /*
+ Only one subclass is logged.
+ */
+ if (event->event_subclass == MYSQL_AUDIT_GENERAL_STATUS &&
+ event_query_command(event))
+ {
+ log_statement(cn, event, "QUERY");
+ cn->query_length= 0; /* So the log_current_query() won't log this again. */
+ cn->log_always= 0;
+ }
+ }
+ else if (event_class == MYSQL_AUDIT_TABLE_CLASS && FILTER(EVENT_TABLE) && cn)
+ {
+ const struct mysql_event_table *event =
+ (const struct mysql_event_table *) ev;
+ if (do_log_user(event->user, (int) SAFE_STRLEN(event->user),
+ cn->proxy, cn->proxy_length, 1))
+ {
+ switch (event->event_subclass)
+ {
+ case MYSQL_AUDIT_TABLE_LOCK:
+ log_table(cn, event, event->read_only ? "READ" : "WRITE");
+ break;
+ case MYSQL_AUDIT_TABLE_CREATE:
+ log_table(cn, event, "CREATE");
+ break;
+ case MYSQL_AUDIT_TABLE_DROP:
+ log_table(cn, event, "DROP");
+ break;
+ case MYSQL_AUDIT_TABLE_RENAME:
+ log_rename(cn, event);
+ break;
+ case MYSQL_AUDIT_TABLE_ALTER:
+ log_table(cn, event, "ALTER");
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else if (event_class == MYSQL_AUDIT_CONNECTION_CLASS &&
+ FILTER(EVENT_CONNECT) && cn)
+ {
+ const struct mysql_event_connection *event =
+ (const struct mysql_event_connection *) ev;
+ switch (event->event_subclass)
+ {
+ case MYSQL_AUDIT_CONNECTION_CONNECT:
+ log_connection(cn, event, event->status ? "FAILED_CONNECT": "CONNECT");
+ if (event->status == 0 && event->proxy_user && event->proxy_user[0])
+ log_proxy(cn, event);
+ break;
+ case MYSQL_AUDIT_CONNECTION_DISCONNECT:
+ if (use_event_data_for_disconnect)
+ log_connection_event(event, "DISCONNECT");
+ else
+ log_connection(&ci_disconnect_buffer, event, "DISCONNECT");
+ break;
+ case MYSQL_AUDIT_CONNECTION_CHANGE_USER:
+ log_connection(cn, event, "CHANGEUSER");
+ if (event->proxy_user && event->proxy_user[0])
+ log_proxy(cn, event);
+ break;
+ default:;
+ }
+ }
+exit_func:
+ /*
+ This must work always, whether logging is ON or not.
+ */
+ if (after_action)
+ {
+ switch (after_action) {
+ case AA_CHANGE_USER:
+ {
+ const struct mysql_event_connection *event =
+ (const struct mysql_event_connection *) ev;
+ change_connection(cn, event);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+
+struct mysql_event_general_v8
+{
+ unsigned int event_class;
+ unsigned int event_subclass;
+ int general_error_code;
+ unsigned long general_thread_id;
+ const char *general_user;
+ unsigned int general_user_length;
+ const char *general_command;
+ unsigned int general_command_length;
+ const char *general_query;
+ unsigned int general_query_length;
+ struct charset_info_st *general_charset;
+ unsigned long long general_time;
+ unsigned long long general_rows;
+};
+
+
+static void auditing_v8(MYSQL_THD thd, struct mysql_event_general_v8 *ev_v8)
+{
+#ifdef __linux__
+#ifdef DBUG_OFF
+ #ifdef __x86_64__
+ static const int cmd_off= 4200;
+ static const int db_off= 120;
+ static const int db_len_off= 128;
+ #else
+ static const int cmd_off= 2668;
+ static const int db_off= 60;
+ static const int db_len_off= 64;
+ #endif /*x86_64*/
+#else
+ #ifdef __x86_64__
+ static const int cmd_off= 4432;
+ static const int db_off= 120;
+ static const int db_len_off= 128;
+ #else
+ static const int cmd_off= 2808;
+ static const int db_off= 64;
+ static const int db_len_off= 68;
+ #endif /*x86_64*/
+#endif /*DBUG_OFF*/
+#endif /* __linux__ */
+
+ struct mysql_event_general event;
+
+ if (ev_v8->event_class != MYSQL_AUDIT_GENERAL_CLASS)
+ return;
+
+ event.event_subclass= ev_v8->event_subclass;
+ event.general_error_code= ev_v8->general_error_code;
+ event.general_thread_id= ev_v8->general_thread_id;
+ event.general_user= ev_v8->general_user;
+ event.general_user_length= ev_v8->general_user_length;
+ event.general_command= ev_v8->general_command;
+ event.general_command_length= ev_v8->general_command_length;
+ event.general_query= ev_v8->general_query;
+ event.general_query_length= ev_v8->general_query_length;
+ event.general_charset= ev_v8->general_charset;
+ event.general_time= ev_v8->general_time;
+ event.general_rows= ev_v8->general_rows;
+ event.database.str= 0;
+ event.database.length= 0;
+
+ if (event.general_query_length > 0)
+ {
+ event.event_subclass= MYSQL_AUDIT_GENERAL_STATUS;
+ event.general_command= "Query";
+ event.general_command_length= 5;
+#ifdef __linux__
+ event.database.str= *(char **) (((char *) thd) + db_off);
+ event.database.length= *(size_t *) (((char *) thd) + db_len_off);
+#endif /*__linux*/
+ }
+#ifdef __linux__
+ else if (*((int *) (((char *)thd) + cmd_off)) == 2)
+ {
+ event.event_subclass= MYSQL_AUDIT_GENERAL_LOG;
+ event.general_command= "Init DB";
+ event.general_command_length= 7;
+ event.general_query= *(char **) (((char *) thd) + db_off);
+ event.general_query_length= *(size_t *) (((char *) thd) + db_len_off);
+ }
+#endif /*__linux*/
+ auditing(thd, ev_v8->event_class, &event);
+}
+
+
+static void auditing_v13(MYSQL_THD thd, unsigned int *ev_v0)
+{
+ struct mysql_event_general event= *(const struct mysql_event_general *) (ev_v0+1);
+
+ if (event.general_query_length > 0)
+ {
+ event.event_subclass= MYSQL_AUDIT_GENERAL_STATUS;
+ event.general_command= "Query";
+ event.general_command_length= 5;
+ }
+ auditing(thd, ev_v0[0], &event);
+}
+
+
+int get_db_mysql57(MYSQL_THD thd, char **name, size_t *len)
+{
+#ifdef __linux__
+ int db_off;
+ int db_len_off;
+ if (debug_server_started)
+ {
+#ifdef __x86_64__
+ db_off= 608;
+ db_len_off= 616;
+#else
+ db_off= 0;
+ db_len_off= 0;
+#endif /*x86_64*/
+ }
+ else
+ {
+#ifdef __x86_64__
+ db_off= 536;
+ db_len_off= 544;
+#else
+ db_off= 0;
+ db_len_off= 0;
+#endif /*x86_64*/
+ }
+
+ *name= *(char **) (((char *) thd) + db_off);
+ *len= *((size_t *) (((char*) thd) + db_len_off));
+ if (*name && (*name)[*len] != 0)
+ return 1;
+ return 0;
+#else
+ return 1;
+#endif
+}
+/*
+ As it's just too difficult to #include "sql_class.h",
+ let's just copy the necessary part of the system_variables
+ structure here.
+*/
+typedef struct loc_system_variables
+{
+ ulong dynamic_variables_version;
+ char* dynamic_variables_ptr;
+ uint dynamic_variables_head; /* largest valid variable offset */
+ uint dynamic_variables_size; /* how many bytes are in use */
+
+ ulonglong max_heap_table_size;
+ ulonglong tmp_table_size;
+ ulonglong long_query_time;
+ ulonglong optimizer_switch;
+ ulonglong sql_mode; ///< which non-standard SQL behaviour should be enabled
+ ulonglong option_bits; ///< OPTION_xxx constants, e.g. OPTION_PROFILING
+ ulonglong join_buff_space_limit;
+ ulonglong log_slow_filter;
+ ulonglong log_slow_verbosity;
+ ulonglong bulk_insert_buff_size;
+ ulonglong join_buff_size;
+ ulonglong sortbuff_size;
+ ulonglong group_concat_max_len;
+ ha_rows select_limit;
+ ha_rows max_join_size;
+ ha_rows expensive_subquery_limit;
+ ulong auto_increment_increment, auto_increment_offset;
+ ulong lock_wait_timeout;
+ ulong join_cache_level;
+ ulong max_allowed_packet;
+ ulong max_error_count;
+ ulong max_length_for_sort_data;
+ ulong max_sort_length;
+ ulong max_tmp_tables;
+ ulong max_insert_delayed_threads;
+ ulong min_examined_row_limit;
+ ulong net_buffer_length;
+ ulong net_interactive_timeout;
+ ulong net_read_timeout;
+ ulong net_retry_count;
+ ulong net_wait_timeout;
+ ulong net_write_timeout;
+ ulong optimizer_prune_level;
+ ulong optimizer_search_depth;
+ ulong preload_buff_size;
+ ulong profiling_history_size;
+ ulong read_buff_size;
+ ulong read_rnd_buff_size;
+ ulong mrr_buff_size;
+ ulong div_precincrement;
+ /* Total size of all buffers used by the subselect_rowid_merge_engine. */
+ ulong rowid_merge_buff_size;
+ ulong max_sp_recursion_depth;
+ ulong default_week_format;
+ ulong max_seeks_for_key;
+ ulong range_alloc_block_size;
+ ulong query_alloc_block_size;
+ ulong query_prealloc_size;
+ ulong trans_alloc_block_size;
+ ulong trans_prealloc_size;
+ ulong log_warnings;
+ /* Flags for slow log filtering */
+ ulong log_slow_rate_limit;
+ ulong binlog_format; ///< binlog format for this thd (see enum_binlog_format)
+ ulong progress_report_time;
+ my_bool binlog_annotate_row_events;
+ my_bool binlog_direct_non_trans_update;
+ my_bool sql_log_bin;
+ ulong completion_type;
+ ulong query_cache_type;
+} LOC_SV;
+
+
+static int init_done= 0;
+
+static void* find_sym(const char *sym)
+{
+#ifdef _WIN32
+ return GetProcAddress(GetModuleHandle("server.dll"),sym);
+#else
+ return dlsym(RTLD_DEFAULT, sym);
+#endif
+}
+
+static int server_audit_init(void *p __attribute__((unused)))
+{
+ if (!serv_ver)
+ {
+ serv_ver= find_sym("server_version");
+ }
+
+ if (!mysql_57_started)
+ {
+ const void *my_hash_init_ptr= find_sym("_my_hash_init");
+ if (!my_hash_init_ptr)
+ {
+ maria_above_5= 1;
+ my_hash_init_ptr= find_sym("my_hash_init2");
+ }
+ if (!my_hash_init_ptr)
+ return 1;
+ }
+
+ if(!(int_mysql_data_home= find_sym("mysql_data_home")))
+ {
+ if(!(int_mysql_data_home= find_sym("?mysql_data_home@@3PADA")))
+ int_mysql_data_home= &default_home;
+ }
+
+ if (!serv_ver)
+ return 1;
+
+ if (!started_mysql)
+ {
+ if (!maria_above_5 && serv_ver[4]=='3' && serv_ver[5]<'3')
+ {
+ mode= 1;
+ mode_readonly= 1;
+ }
+ }
+
+ if (gethostname(servhost, sizeof(servhost)))
+ strcpy(servhost, "unknown");
+
+ servhost_len= (uint)strlen(servhost);
+
+ logger_init_mutexes();
+#ifdef HAVE_PSI_INTERFACE
+ if (PSI_server)
+ PSI_server->register_mutex("server_audit", mutex_key_list, 1);
+#endif
+ mysql_prlock_init(key_LOCK_operations, &lock_operations);
+ flogger_mutex_init(key_LOCK_operations, &lock_atomic, MY_MUTEX_INIT_FAST);
+ flogger_mutex_init(key_LOCK_operations, &lock_bigbuffer, MY_MUTEX_INIT_FAST);
+
+ coll_init(&incl_user_coll);
+ coll_init(&excl_user_coll);
+
+ if (incl_users)
+ {
+ if (excl_users)
+ {
+ incl_users= excl_users= NULL;
+ error_header();
+ fprintf(stderr, "INCL_DML_USERS and EXCL_DML_USERS specified"
+ " simultaneously - both set to empty\n");
+ }
+ update_incl_users(NULL, NULL, NULL, &incl_users);
+ }
+ else if (excl_users)
+ {
+ update_excl_users(NULL, NULL, NULL, &excl_users);
+ }
+
+ error_header();
+ fprintf(stderr, "MariaDB Audit Plugin version %s%s STARTED.\n",
+ PLUGIN_STR_VERSION, PLUGIN_DEBUG_VERSION);
+
+ /* The Query Cache shadows TABLE events if the result is taken from it */
+ /* so we warn users if both Query Cashe and TABLE events enabled. */
+ if (!started_mysql && FILTER(EVENT_TABLE))
+ {
+ ulonglong *qc_size= (ulonglong *) dlsym(RTLD_DEFAULT, "query_cache_size");
+ if (qc_size == NULL || *qc_size != 0)
+ {
+ struct loc_system_variables *g_sys_var=
+ (struct loc_system_variables *) dlsym(RTLD_DEFAULT,
+ "global_system_variables");
+ if (g_sys_var && g_sys_var->query_cache_type != 0)
+ {
+ error_header();
+ fprintf(stderr, "Query cache is enabled with the TABLE events."
+ " Some table reads can be veiled.");
+ }
+ }
+ }
+
+ ci_disconnect_buffer.header= 10;
+ ci_disconnect_buffer.thread_id= 0;
+ ci_disconnect_buffer.query_id= 0;
+ ci_disconnect_buffer.db_length= 0;
+ ci_disconnect_buffer.user_length= 0;
+ ci_disconnect_buffer.host_length= 0;
+ ci_disconnect_buffer.ip_length= 0;
+ ci_disconnect_buffer.query= empty_str;
+ ci_disconnect_buffer.query_length= 0;
+
+ if (logging)
+ start_logging();
+
+ init_done= 1;
+ return 0;
+}
+
+
+static int server_audit_init_mysql(void *p)
+{
+ started_mysql= 1;
+ mode= 1;
+ mode_readonly= 1;
+ return server_audit_init(p);
+}
+
+
+static int server_audit_deinit(void *p __attribute__((unused)))
+{
+ if (!init_done)
+ return 0;
+
+ init_done= 0;
+ coll_free(&incl_user_coll);
+ coll_free(&excl_user_coll);
+
+ if (output_type == OUTPUT_FILE && logfile)
+ logger_close(logfile);
+ else if (output_type == OUTPUT_SYSLOG)
+ closelog();
+
+ (void) free(big_buffer);
+ mysql_prlock_destroy(&lock_operations);
+ flogger_mutex_destroy(&lock_atomic);
+ flogger_mutex_destroy(&lock_bigbuffer);
+
+ error_header();
+ fprintf(stderr, "STOPPED\n");
+ return 0;
+}
+
+
+static void rotate_log(MYSQL_THD thd __attribute__((unused)),
+ struct st_mysql_sys_var *var __attribute__((unused)),
+ void *var_ptr __attribute__((unused)),
+ const void *save __attribute__((unused)))
+{
+ if (output_type == OUTPUT_FILE && logfile && *(my_bool*) save)
+ (void) logger_rotate(logfile);
+}
+
+
+static struct st_mysql_audit mysql_descriptor =
+{
+ MYSQL_AUDIT_INTERFACE_VERSION,
+ NULL,
+ auditing,
+ { MYSQL_AUDIT_GENERAL_CLASSMASK | MYSQL_AUDIT_CONNECTION_CLASSMASK }
+};
+
+
+mysql_declare_plugin(server_audit)
+{
+ MYSQL_AUDIT_PLUGIN,
+ &mysql_descriptor,
+ "SERVER_AUDIT",
+ " Alexey Botchkov (MariaDB Corporation)",
+ "Audit the server activity",
+ PLUGIN_LICENSE_GPL,
+ server_audit_init_mysql,
+ server_audit_deinit,
+ PLUGIN_VERSION,
+ audit_status,
+ vars,
+ NULL,
+ 0
+}
+mysql_declare_plugin_end;
+
+
+static struct st_mysql_audit maria_descriptor =
+{
+ MYSQL_AUDIT_INTERFACE_VERSION,
+ NULL,
+ auditing,
+ { MYSQL_AUDIT_GENERAL_CLASSMASK |
+ MYSQL_AUDIT_TABLE_CLASSMASK |
+ MYSQL_AUDIT_CONNECTION_CLASSMASK }
+};
+maria_declare_plugin(server_audit)
+{
+ MYSQL_AUDIT_PLUGIN,
+ &maria_descriptor,
+ "SERVER_AUDIT",
+ "Alexey Botchkov (MariaDB Corporation)",
+ "Audit the server activity",
+ PLUGIN_LICENSE_GPL,
+ server_audit_init,
+ server_audit_deinit,
+ PLUGIN_VERSION,
+ audit_status,
+ vars,
+ PLUGIN_STR_VERSION,
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
+
+
+static void mark_always_logged(MYSQL_THD thd)
+{
+ struct connection_info *cn;
+ if (thd && (cn= get_loc_info(thd)))
+ cn->log_always= 1;
+}
+
+
+static void log_current_query(MYSQL_THD thd)
+{
+ struct connection_info *cn;
+ if (!thd)
+ return;
+ cn= get_loc_info(thd);
+ if (!ci_needs_setup(cn) && cn->query_length)
+ {
+ cn->log_always= 1;
+ log_statement_ex(cn, cn->query_time, thd_get_thread_id(thd),
+ cn->query, cn->query_length, 0, "QUERY", 0);
+ cn->log_always= 0;
+ }
+}
+
+
+static void update_file_path(MYSQL_THD thd,
+ struct st_mysql_sys_var *var __attribute__((unused)),
+ void *var_ptr __attribute__((unused)), const void *save)
+{
+ char *new_name= (*(char **) save) ? *(char **) save : empty_str;
+
+ ADD_ATOMIC(internal_stop_logging, 1);
+ error_header();
+ fprintf(stderr, "Log file name was changed to '%s'.\n", new_name);
+
+ if (!maria_55_started || !debug_server_started)
+ mysql_prlock_wrlock(&lock_operations);
+
+ if (logging)
+ log_current_query(thd);
+
+ if (logging && output_type == OUTPUT_FILE)
+ {
+ char *sav_path= file_path;
+
+ file_path= new_name;
+ stop_logging();
+ if (start_logging())
+ {
+ file_path= sav_path;
+ error_header();
+ fprintf(stderr, "Reverting log filename back to '%s'.\n", file_path);
+ logging= (start_logging() == 0);
+ if (!logging)
+ {
+ error_header();
+ fprintf(stderr, "Logging was disabled..\n");
+ CLIENT_ERROR(1, "Logging was disabled.", MYF(ME_WARNING));
+ }
+ goto exit_func;
+ }
+ }
+
+ strncpy(path_buffer, new_name, sizeof(path_buffer)-1);
+ path_buffer[sizeof(path_buffer)-1]= 0;
+ file_path= path_buffer;
+exit_func:
+ if (!maria_55_started || !debug_server_started)
+ mysql_prlock_unlock(&lock_operations);
+ ADD_ATOMIC(internal_stop_logging, -1);
+}
+
+
+static void update_file_rotations(MYSQL_THD thd __attribute__((unused)),
+ struct st_mysql_sys_var *var __attribute__((unused)),
+ void *var_ptr __attribute__((unused)), const void *save)
+{
+ rotations= *(unsigned int *) save;
+ error_header();
+ fprintf(stderr, "Log file rotations was changed to '%d'.\n", rotations);
+
+ if (!logging || output_type != OUTPUT_FILE)
+ return;
+
+ mysql_prlock_wrlock(&lock_operations);
+ logfile->rotations= rotations;
+ mysql_prlock_unlock(&lock_operations);
+}
+
+
+static void update_file_rotate_size(MYSQL_THD thd __attribute__((unused)),
+ struct st_mysql_sys_var *var __attribute__((unused)),
+ void *var_ptr __attribute__((unused)), const void *save)
+{
+ file_rotate_size= *(unsigned long long *) save;
+ error_header();
+ fprintf(stderr, "Log file rotate size was changed to '%lld'.\n",
+ file_rotate_size);
+
+ if (!logging || output_type != OUTPUT_FILE)
+ return;
+
+ mysql_prlock_wrlock(&lock_operations);
+ logfile->size_limit= file_rotate_size;
+ mysql_prlock_unlock(&lock_operations);
+}
+
+
+static int check_users(void *save, struct st_mysql_value *value,
+ size_t s, const char *name)
+{
+ const char *users;
+ int len= 0;
+
+ users= value->val_str(value, NULL, &len);
+ if ((size_t) len > s)
+ {
+ error_header();
+ fprintf(stderr,
+ "server_audit_%s_users value can't be longer than %zu characters.\n",
+ name, s);
+ return 1;
+ }
+ *((const char**)save)= users;
+ return 0;
+}
+
+static int check_incl_users(MYSQL_THD thd __attribute__((unused)),
+ struct st_mysql_sys_var *var __attribute__((unused)),
+ void *save, struct st_mysql_value *value)
+{
+ return check_users(save, value, sizeof(incl_user_buffer), "incl");
+}
+
+static int check_excl_users(MYSQL_THD thd __attribute__((unused)),
+ struct st_mysql_sys_var *var __attribute__((unused)),
+ void *save, struct st_mysql_value *value)
+{
+ return check_users(save, value, sizeof(excl_user_buffer), "excl");
+}
+
+
+static void update_incl_users(MYSQL_THD thd,
+ struct st_mysql_sys_var *var __attribute__((unused)),
+ void *var_ptr __attribute__((unused)), const void *save)
+{
+ char *new_users= (*(char **) save) ? *(char **) save : empty_str;
+ size_t new_len= strlen(new_users) + 1;
+ if (!maria_55_started || !debug_server_started)
+ mysql_prlock_wrlock(&lock_operations);
+ mark_always_logged(thd);
+
+ if (new_len > sizeof(incl_user_buffer))
+ new_len= sizeof(incl_user_buffer);
+
+ memcpy(incl_user_buffer, new_users, new_len - 1);
+ incl_user_buffer[new_len - 1]= 0;
+
+ incl_users= incl_user_buffer;
+ user_coll_fill(&incl_user_coll, incl_users, &excl_user_coll, 1);
+ error_header();
+ fprintf(stderr, "server_audit_incl_users set to '%s'.\n", incl_users);
+ if (!maria_55_started || !debug_server_started)
+ mysql_prlock_unlock(&lock_operations);
+}
+
+
+static void update_excl_users(MYSQL_THD thd __attribute__((unused)),
+ struct st_mysql_sys_var *var __attribute__((unused)),
+ void *var_ptr __attribute__((unused)), const void *save)
+{
+ char *new_users= (*(char **) save) ? *(char **) save : empty_str;
+ size_t new_len= strlen(new_users) + 1;
+ if (!maria_55_started || !debug_server_started)
+ mysql_prlock_wrlock(&lock_operations);
+ mark_always_logged(thd);
+
+ if (new_len > sizeof(excl_user_buffer))
+ new_len= sizeof(excl_user_buffer);
+
+ memcpy(excl_user_buffer, new_users, new_len - 1);
+ excl_user_buffer[new_len - 1]= 0;
+
+ excl_users= excl_user_buffer;
+ user_coll_fill(&excl_user_coll, excl_users, &incl_user_coll, 0);
+ error_header();
+ fprintf(stderr, "server_audit_excl_users set to '%s'.\n", excl_users);
+ if (!maria_55_started || !debug_server_started)
+ mysql_prlock_unlock(&lock_operations);
+}
+
+
+static void update_output_type(MYSQL_THD thd,
+ struct st_mysql_sys_var *var __attribute__((unused)),
+ void *var_ptr __attribute__((unused)), const void *save)
+{
+ ulong new_output_type= *((ulong *) save);
+ if (output_type == new_output_type)
+ return;
+
+ ADD_ATOMIC(internal_stop_logging, 1);
+ mysql_prlock_wrlock(&lock_operations);
+ if (logging)
+ {
+ log_current_query(thd);
+ stop_logging();
+ }
+
+ output_type= new_output_type;
+ error_header();
+ fprintf(stderr, "Output was redirected to '%s'\n",
+ output_type_names[output_type]);
+
+ if (logging)
+ start_logging();
+ mysql_prlock_unlock(&lock_operations);
+ ADD_ATOMIC(internal_stop_logging, -1);
+}
+
+
+static void update_syslog_facility(MYSQL_THD thd __attribute__((unused)),
+ struct st_mysql_sys_var *var __attribute__((unused)),
+ void *var_ptr __attribute__((unused)), const void *save)
+{
+ ulong new_facility= *((ulong *) save);
+ if (syslog_facility == new_facility)
+ return;
+
+ mark_always_logged(thd);
+ error_header();
+ fprintf(stderr, "SysLog facility was changed from '%s' to '%s'.\n",
+ syslog_facility_names[syslog_facility],
+ syslog_facility_names[new_facility]);
+ syslog_facility= new_facility;
+}
+
+
+static void update_syslog_priority(MYSQL_THD thd __attribute__((unused)),
+ struct st_mysql_sys_var *var __attribute__((unused)),
+ void *var_ptr __attribute__((unused)), const void *save)
+{
+ ulong new_priority= *((ulong *) save);
+ if (syslog_priority == new_priority)
+ return;
+
+ mysql_prlock_wrlock(&lock_operations);
+ mark_always_logged(thd);
+ mysql_prlock_unlock(&lock_operations);
+ error_header();
+ fprintf(stderr, "SysLog priority was changed from '%s' to '%s'.\n",
+ syslog_priority_names[syslog_priority],
+ syslog_priority_names[new_priority]);
+ syslog_priority= new_priority;
+}
+
+
+static void update_logging(MYSQL_THD thd,
+ struct st_mysql_sys_var *var __attribute__((unused)),
+ void *var_ptr __attribute__((unused)), const void *save)
+{
+ char new_logging= *(char *) save;
+ if (new_logging == logging)
+ return;
+
+ ADD_ATOMIC(internal_stop_logging, 1);
+ if (!maria_55_started || !debug_server_started)
+ mysql_prlock_wrlock(&lock_operations);
+ if ((logging= new_logging))
+ {
+ start_logging();
+ if (!logging)
+ {
+ CLIENT_ERROR(1, "Logging was disabled.", MYF(ME_WARNING));
+ }
+ mark_always_logged(thd);
+ }
+ else
+ {
+ log_current_query(thd);
+ stop_logging();
+ }
+
+ if (!maria_55_started || !debug_server_started)
+ mysql_prlock_unlock(&lock_operations);
+ ADD_ATOMIC(internal_stop_logging, -1);
+}
+
+
+static void update_mode(MYSQL_THD thd __attribute__((unused)),
+ struct st_mysql_sys_var *var __attribute__((unused)),
+ void *var_ptr __attribute__((unused)), const void *save)
+{
+ unsigned int new_mode= *(unsigned int *) save;
+ if (mode_readonly || new_mode == mode)
+ return;
+
+ ADD_ATOMIC(internal_stop_logging, 1);
+ if (!maria_55_started || !debug_server_started)
+ mysql_prlock_wrlock(&lock_operations);
+ mark_always_logged(thd);
+ error_header();
+ fprintf(stderr, "Logging mode was changed from %d to %d.\n", mode, new_mode);
+ mode= new_mode;
+ if (!maria_55_started || !debug_server_started)
+ mysql_prlock_unlock(&lock_operations);
+ ADD_ATOMIC(internal_stop_logging, -1);
+}
+
+
+static void update_syslog_ident(MYSQL_THD thd __attribute__((unused)),
+ struct st_mysql_sys_var *var __attribute__((unused)),
+ void *var_ptr __attribute__((unused)), const void *save)
+{
+ char *new_ident= (*(char **) save) ? *(char **) save : empty_str;
+ strncpy(syslog_ident_buffer, new_ident, sizeof(syslog_ident_buffer)-1);
+ syslog_ident_buffer[sizeof(syslog_ident_buffer)-1]= 0;
+ syslog_ident= syslog_ident_buffer;
+ error_header();
+ fprintf(stderr, "SYSYLOG ident was changed to '%s'\n", syslog_ident);
+ mysql_prlock_wrlock(&lock_operations);
+ mark_always_logged(thd);
+ if (logging && output_type == OUTPUT_SYSLOG)
+ {
+ stop_logging();
+ start_logging();
+ }
+ mysql_prlock_unlock(&lock_operations);
+}
+
+
+struct st_my_thread_var *loc_thread_var(void)
+{
+ return 0;
+}
+
+
+
+#ifdef _WIN32
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ if (fdwReason != DLL_PROCESS_ATTACH)
+ return 1;
+
+ serv_ver= server_version;
+#else
+void __attribute__ ((constructor)) audit_plugin_so_init(void)
+{
+ serv_ver= server_version;
+#endif /*_WIN32*/
+
+ if (!serv_ver)
+ goto exit;
+
+ started_mariadb= strstr(serv_ver, "MariaDB") != 0;
+ debug_server_started= strstr(serv_ver, "debug") != 0;
+
+ if (started_mariadb)
+ {
+ if (serv_ver[0] == '1')
+ use_event_data_for_disconnect= 1;
+ else
+ maria_55_started= 1;
+ }
+ else
+ {
+ /* Started MySQL. */
+ if (serv_ver[0] == '5' && serv_ver[2] == '5')
+ {
+ int sc= serv_ver[4] - '0';
+ if (serv_ver[5] >= '0' && serv_ver[5] <= '9')
+ sc= sc * 10 + serv_ver[5] - '0';
+ if (sc <= 10)
+ {
+ mysql_descriptor.interface_version= 0x0200;
+ mysql_descriptor.event_notify= (void *) auditing_v8;
+ }
+ else if (sc < 14)
+ {
+ mysql_descriptor.interface_version= 0x0200;
+ mysql_descriptor.event_notify= (void *) auditing_v13;
+ }
+ }
+ else if (serv_ver[0] == '5' && serv_ver[2] == '6')
+ {
+ int sc= serv_ver[4] - '0';
+ if (serv_ver[5] >= '0' && serv_ver[5] <= '9')
+ sc= sc * 10 + serv_ver[5] - '0';
+ if (sc >= 24)
+ use_event_data_for_disconnect= 1;
+ }
+ else if ((serv_ver[0] == '5' && serv_ver[2] == '7') ||
+ (serv_ver[0] == '8' && serv_ver[2] == '0'))
+ {
+ mysql_57_started= 1;
+ _mysql_plugin_declarations_[0].info= mysql_v4_descriptor;
+ use_event_data_for_disconnect= 1;
+ }
+ MYSQL_SYSVAR_NAME(loc_info).flags= PLUGIN_VAR_STR | PLUGIN_VAR_THDLOCAL |
+ PLUGIN_VAR_READONLY | PLUGIN_VAR_MEMALLOC;
+ }
+
+ memset(locinfo_ini_value, 'O', sizeof(locinfo_ini_value)-1);
+ locinfo_ini_value[sizeof(locinfo_ini_value)-1]= 0;
+
+exit:
+#ifdef _WIN32
+ return 1;
+#else
+ return;
+#endif
+}
+
diff --git a/plugin/server_audit/test_audit_v4.c b/plugin/server_audit/test_audit_v4.c
new file mode 100644
index 00000000..f37d8c7c
--- /dev/null
+++ b/plugin/server_audit/test_audit_v4.c
@@ -0,0 +1,163 @@
+#define PLUGIN_CONTEXT
+
+/* Can't use <my_global.h> as this includes plugin.h */
+#include <stdio.h>
+
+typedef void *MYSQL_THD;
+struct st_mysql_const_lex_string
+{
+ const char *str;
+ size_t length;
+};
+typedef struct st_mysql_const_lex_string MYSQL_LEX_CSTRING;
+enum enum_sql_command{ SQLCOM_A, SQLCOM_B };
+enum enum_server_command{ SERVCOM_A, SERVCOM_B };
+
+#include "plugin_audit_v4.h"
+
+extern void auditing(MYSQL_THD thd, unsigned int event_class, const void *ev);
+extern int get_db_mysql57(MYSQL_THD thd, char **name, size_t *len);
+
+
+struct mysql_event_general_302
+{
+ unsigned int event_subclass;
+ int general_error_code;
+ unsigned long general_thread_id;
+ const char *general_user;
+ unsigned int general_user_length;
+ const char *general_command;
+ unsigned int general_command_length;
+ const char *general_query;
+ unsigned int general_query_length;
+ struct charset_info_st *general_charset;
+ unsigned long long general_time;
+ unsigned long long general_rows;
+ unsigned long long query_id;
+ char *database;
+ size_t database_length;
+};
+
+
+static int auditing_v4(MYSQL_THD thd, mysql_event_class_t class, const void *ev)
+{
+ int *subclass= (int *)ev;
+ struct mysql_event_general_302 ev_302;
+ int subclass_v3, subclass_orig;
+
+ if (class != MYSQL_AUDIT_GENERAL_CLASS &&
+ class != MYSQL_AUDIT_CONNECTION_CLASS)
+ return 0;
+
+ subclass_orig= *subclass;
+
+ if (class == MYSQL_AUDIT_GENERAL_CLASS)
+ {
+ struct mysql_event_general *event= (struct mysql_event_general *) ev;
+ ev_302.general_error_code= event->general_error_code;
+ ev_302.general_thread_id= event->general_thread_id;
+ ev_302.general_user= event->general_user.str;
+ ev_302.general_user_length= (unsigned int)event->general_user.length;
+ ev_302.general_command= event->general_command.str;
+ ev_302.general_command_length= (unsigned int)event->general_command.length;
+ ev_302.general_query= event->general_query.str;
+ ev_302.general_query_length= (unsigned int)event->general_query.length;
+ ev_302.general_charset= event->general_charset;
+ ev_302.general_time= event->general_time;
+ ev_302.general_rows= event->general_rows;
+ if (get_db_mysql57(thd, &ev_302.database, &ev_302.database_length))
+ {
+ ev_302.database= 0;
+ ev_302.database_length= 0;
+ }
+ ev= &ev_302;
+ switch (subclass_orig)
+ {
+ case MYSQL_AUDIT_GENERAL_LOG:
+ subclass_v3= 0;
+ ev_302.event_subclass= 0;
+ break;
+ case MYSQL_AUDIT_GENERAL_ERROR:
+ subclass_v3= 1;
+ ev_302.event_subclass= 1;
+ break;
+ case MYSQL_AUDIT_GENERAL_RESULT:
+ subclass_v3= 2;
+ ev_302.event_subclass= 2;
+ break;
+ case MYSQL_AUDIT_GENERAL_STATUS:
+ {
+ subclass_v3= 3;
+ ev_302.event_subclass= 3;
+ break;
+ }
+ default:
+ return 0;
+ }
+ }
+ else /* if (class == MYSQL_AUDIT_CONNECTION_CLASS) */
+ {
+ switch (subclass_orig)
+ {
+ case MYSQL_AUDIT_CONNECTION_CONNECT:
+ subclass_v3= 0;
+ break;
+ case MYSQL_AUDIT_CONNECTION_DISCONNECT:
+ subclass_v3= 1;
+ break;
+ default:
+ return 0;
+ }
+ }
+
+ *subclass= subclass_v3;
+
+ auditing(thd, (int) class, ev);
+
+ *subclass= subclass_orig;
+ return 0;
+}
+
+
+static struct st_mysql_audit mysql_descriptor =
+{
+ MYSQL_AUDIT_INTERFACE_VERSION,
+ NULL,
+ auditing_v4,
+ { (unsigned long) MYSQL_AUDIT_GENERAL_ALL,
+ (unsigned long) MYSQL_AUDIT_CONNECTION_ALL,
+ (unsigned long) MYSQL_AUDIT_PARSE_ALL,
+ 0, /* This event class is currently not supported. */
+ 0, /* This event class is currently not supported. */
+ (unsigned long) MYSQL_AUDIT_GLOBAL_VARIABLE_ALL,
+ (unsigned long) MYSQL_AUDIT_SERVER_STARTUP_ALL,
+ (unsigned long) MYSQL_AUDIT_SERVER_SHUTDOWN_ALL,
+ (unsigned long) MYSQL_AUDIT_COMMAND_ALL,
+ (unsigned long) MYSQL_AUDIT_QUERY_ALL,
+ (unsigned long) MYSQL_AUDIT_STORED_PROGRAM_ALL }
+#ifdef WHEN_MYSQL_BUG_FIXED
+ /*
+ By this moment MySQL just sends no notifications at all
+ when we request only those we actually need.
+ So we have to request everything and filter them inside the
+ handling function.
+ */
+ { (unsigned long) MYSQL_AUDIT_GENERAL_ALL,
+ (unsigned long) (MYSQL_AUDIT_CONNECTION_CONNECT |
+ MYSQL_AUDIT_CONNECTION_DISCONNECT),
+ 0,
+ 0, /* This event class is currently not supported. */
+ 0, /* This event class is currently not supported. */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ }
+#endif /*WHEN_MYSQL_BUG_FIXED*/
+};
+
+
+void *mysql_v4_descriptor= &mysql_descriptor;
+
diff --git a/plugin/simple_password_check/CMakeLists.txt b/plugin/simple_password_check/CMakeLists.txt
new file mode 100644
index 00000000..f41024d2
--- /dev/null
+++ b/plugin/simple_password_check/CMakeLists.txt
@@ -0,0 +1 @@
+MYSQL_ADD_PLUGIN(simple_password_check simple_password_check.c MODULE_ONLY)
diff --git a/plugin/simple_password_check/simple_password_check.c b/plugin/simple_password_check/simple_password_check.c
new file mode 100644
index 00000000..65d017e2
--- /dev/null
+++ b/plugin/simple_password_check/simple_password_check.c
@@ -0,0 +1,117 @@
+/* Copyright (c) 2014, Sergei Golubchik and MariaDB
+ Copyright (c) 2012, 2013, Oracle and/or its affiliates.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include <mysqld_error.h>
+#include <my_attribute.h>
+#include <mysql/plugin_password_validation.h>
+#include <ctype.h>
+#include <string.h>
+
+static unsigned min_length, min_digits, min_letters, min_others;
+
+static int validate(const MYSQL_CONST_LEX_STRING *username,
+ const MYSQL_CONST_LEX_STRING *password)
+{
+ unsigned digits=0 , uppers=0 , lowers=0, others=0, length= (unsigned)password->length;
+ const char *ptr= password->str, *end= ptr + length;
+
+ if (strncmp(password->str, username->str, length) == 0)
+ return 1;
+
+ /* everything non-ascii is the "other" character and is good for the password */
+ for(; ptr < end; ptr++)
+ {
+ if (isdigit(*ptr))
+ digits++;
+ else if (isupper(*ptr))
+ uppers++;
+ else if (islower(*ptr))
+ lowers++;
+ else
+ others++;
+ }
+ /* remember TRUE means the password failed the validation */
+ return length < min_length ||
+ uppers < min_letters ||
+ lowers < min_letters ||
+ digits < min_digits ||
+ others < min_others;
+}
+
+static void fix_min_length(MYSQL_THD thd __attribute__((unused)),
+ struct st_mysql_sys_var *var
+ __attribute__((unused)),
+ void *var_ptr, const void *save)
+{
+ unsigned int new_min_length;
+ *((unsigned int *)var_ptr)= *((unsigned int *)save);
+ new_min_length= min_digits + 2 * min_letters + min_others;
+ if (min_length < new_min_length)
+ {
+ my_printf_error(ER_TRUNCATED_WRONG_VALUE,
+ "Adjusted the value of simple_password_check_minimal_length "
+ "from %u to %u", ME_WARNING, min_length, new_min_length);
+ min_length= new_min_length;
+ }
+}
+
+
+static MYSQL_SYSVAR_UINT(minimal_length, min_length, PLUGIN_VAR_RQCMDARG,
+ "Minimal required password length", NULL, fix_min_length, 8, 0, 1000, 1);
+
+static MYSQL_SYSVAR_UINT(digits, min_digits, PLUGIN_VAR_RQCMDARG,
+ "Minimal required number of digits", NULL, fix_min_length, 1, 0, 1000, 1);
+
+static MYSQL_SYSVAR_UINT(letters_same_case, min_letters, PLUGIN_VAR_RQCMDARG,
+ "Minimal required number of letters of the same letter case."
+ "This limit is applied separately to upper-case and lower-case letters",
+ NULL, fix_min_length, 1, 0, 1000, 1);
+
+static MYSQL_SYSVAR_UINT(other_characters, min_others, PLUGIN_VAR_RQCMDARG,
+ "Minimal required number of other (not letters or digits) characters",
+ NULL, fix_min_length, 1, 0, 1000, 1);
+
+static struct st_mysql_sys_var* sysvars[]= {
+ MYSQL_SYSVAR(minimal_length),
+ MYSQL_SYSVAR(digits),
+ MYSQL_SYSVAR(letters_same_case),
+ MYSQL_SYSVAR(other_characters),
+ NULL
+};
+
+static struct st_mariadb_password_validation info=
+{
+ MariaDB_PASSWORD_VALIDATION_INTERFACE_VERSION,
+ validate
+};
+
+maria_declare_plugin(simple_password_check)
+{
+ MariaDB_PASSWORD_VALIDATION_PLUGIN,
+ &info,
+ "simple_password_check",
+ "Sergei Golubchik",
+ "Simple password strength checks",
+ PLUGIN_LICENSE_GPL,
+ NULL,
+ NULL,
+ 0x0100,
+ NULL,
+ sysvars,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
diff --git a/plugin/sql_errlog/CMakeLists.txt b/plugin/sql_errlog/CMakeLists.txt
new file mode 100644
index 00000000..10754f2a
--- /dev/null
+++ b/plugin/sql_errlog/CMakeLists.txt
@@ -0,0 +1,16 @@
+# Copyright (C) 2012 Monty Program Ab.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
+
+MYSQL_ADD_PLUGIN(sql_errlog sql_errlog.c MODULE_ONLY)
diff --git a/plugin/sql_errlog/sql_errlog.c b/plugin/sql_errlog/sql_errlog.c
new file mode 100644
index 00000000..e0ebd6b7
--- /dev/null
+++ b/plugin/sql_errlog/sql_errlog.c
@@ -0,0 +1,163 @@
+/* Copyright (C) 2012 Monty Program Ab.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include <mysql/plugin_audit.h>
+#include <stdio.h>
+#include <time.h>
+#include <mysql/service_logger.h>
+
+/*
+ Disable __attribute__() on non-gcc compilers.
+*/
+#if !defined(__attribute__) && !defined(__GNUC__)
+#define __attribute__(A)
+#endif
+
+#ifdef _WIN32
+#define localtime_r(a, b) localtime_s(b, a)
+#endif /*WIN32*/
+
+/*
+ rate 0 means the logging was disabled.
+*/
+
+
+static char *filename;
+static unsigned int rate;
+static unsigned long long size_limit;
+static unsigned int rotations;
+static char rotate;
+
+static unsigned int count;
+LOGGER_HANDLE *logfile;
+
+static void rotate_log(MYSQL_THD thd, struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save);
+
+static MYSQL_SYSVAR_UINT(rate, rate, PLUGIN_VAR_RQCMDARG,
+ "Sampling rate. If set to 0(zero), the logging is disabled.", NULL, NULL,
+ 1, 0, 1000000, 1);
+
+static MYSQL_SYSVAR_ULONGLONG(size_limit, size_limit,
+ PLUGIN_VAR_READONLY, "Log file size limit", NULL, NULL,
+ 1000000, 100, ((long long) 0x7FFFFFFFFFFFFFFFLL), 1);
+
+static MYSQL_SYSVAR_UINT(rotations, rotations,
+ PLUGIN_VAR_READONLY, "Number of rotations before log is removed.",
+ NULL, NULL, 9, 1, 999, 1);
+
+static MYSQL_SYSVAR_BOOL(rotate, rotate,
+ PLUGIN_VAR_OPCMDARG, "Force log rotation", NULL, rotate_log,
+ 0);
+
+static MYSQL_SYSVAR_STR(filename, filename,
+ PLUGIN_VAR_READONLY | PLUGIN_VAR_RQCMDARG,
+ "The file to log sql errors to", NULL, NULL,
+ "sql_errors.log");
+
+static struct st_mysql_sys_var* vars[] = {
+ MYSQL_SYSVAR(rate),
+ MYSQL_SYSVAR(size_limit),
+ MYSQL_SYSVAR(rotations),
+ MYSQL_SYSVAR(rotate),
+ MYSQL_SYSVAR(filename),
+ NULL
+};
+
+
+static void log_sql_errors(MYSQL_THD thd __attribute__((unused)),
+ unsigned int event_class __attribute__((unused)),
+ const void *ev)
+{
+ const struct mysql_event_general *event =
+ (const struct mysql_event_general*)ev;
+ if (rate &&
+ event->event_subclass == MYSQL_AUDIT_GENERAL_ERROR)
+ {
+ if (++count >= rate)
+ {
+ struct tm t;
+ time_t event_time = event->general_time;
+
+ count = 0;
+ (void) localtime_r(&event_time, &t);
+ logger_printf(logfile, "%04d-%02d-%02d %2d:%02d:%02d "
+ "%s ERROR %d: %s : %s\n",
+ t.tm_year + 1900, t.tm_mon + 1,
+ t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec,
+ event->general_user, event->general_error_code,
+ event->general_command, event->general_query);
+ }
+ }
+}
+
+
+static int sql_error_log_init(void *p __attribute__((unused)))
+{
+ logger_init_mutexes();
+
+ logfile= logger_open(filename, size_limit, rotations);
+ if (logfile == NULL) {
+ fprintf(stderr, "Could not create file '%s'\n",
+ filename);
+ return 1;
+ }
+ count = 0;
+ return 0;
+}
+
+
+static int sql_error_log_deinit(void *p __attribute__((unused)))
+{
+ if (logfile)
+ logger_close(logfile);
+ return 0;
+}
+
+
+static void rotate_log(MYSQL_THD thd __attribute__((unused)),
+ struct st_mysql_sys_var *var __attribute__((unused)),
+ void *var_ptr __attribute__((unused)),
+ const void *save __attribute__((unused)))
+{
+ (void) logger_rotate(logfile);
+}
+
+
+static struct st_mysql_audit descriptor =
+{
+ MYSQL_AUDIT_INTERFACE_VERSION,
+ NULL,
+ log_sql_errors,
+ { MYSQL_AUDIT_GENERAL_CLASSMASK }
+};
+
+maria_declare_plugin(sql_errlog)
+{
+ MYSQL_AUDIT_PLUGIN,
+ &descriptor,
+ "SQL_ERROR_LOG",
+ "Alexey Botchkov",
+ "Log SQL level errors to a file with rotation",
+ PLUGIN_LICENSE_GPL,
+ sql_error_log_init,
+ sql_error_log_deinit,
+ 0x0100,
+ NULL,
+ vars,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
diff --git a/plugin/test_sql_service/CMakeLists.txt b/plugin/test_sql_service/CMakeLists.txt
new file mode 100644
index 00000000..aa9ecfe6
--- /dev/null
+++ b/plugin/test_sql_service/CMakeLists.txt
@@ -0,0 +1,18 @@
+# Copyright (C) 2013 Alexey Botchkov and SkySQL Ab
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+SET(SOURCES test_sql_service.c)
+
+MYSQL_ADD_PLUGIN(test_sql_service ${SOURCES} MODULE_ONLY RECOMPILE_FOR_EMBEDDED)
diff --git a/plugin/test_sql_service/COPYING b/plugin/test_sql_service/COPYING
new file mode 100644
index 00000000..6e475df5
--- /dev/null
+++ b/plugin/test_sql_service/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 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.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, 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 software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, 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 redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+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 give any other recipients of the Program a copy of this License
+along with the Program.
+
+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 Program or any portion
+of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+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 Program, 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 Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) 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; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, 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 executable. 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.
+
+If distribution of executable or 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 counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program 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.
+
+ 5. 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 Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program 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.
+
+ 7. 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 Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program 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 Program.
+
+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.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program 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.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the 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 Program
+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 Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, 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
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), 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 Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. 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 program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/plugin/test_sql_service/test_sql_service.c b/plugin/test_sql_service/test_sql_service.c
new file mode 100644
index 00000000..062f10fc
--- /dev/null
+++ b/plugin/test_sql_service/test_sql_service.c
@@ -0,0 +1,145 @@
+/* Copyright (C) 2019, Alexey Botchkov and MariaDB Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+
+#define PLUGIN_VERSION 0x100
+#define PLUGIN_STR_VERSION "1.0.0"
+
+#define _my_thread_var loc_thread_var
+
+#include <my_config.h>
+#include <assert.h>
+#include <my_global.h>
+#include <my_base.h>
+#include <typelib.h>
+//#include <mysql_com.h> /* for enum enum_server_command */
+#include <mysql/plugin.h>
+#include <mysql/plugin_audit.h>
+//#include <string.h>
+
+
+LEX_STRING * thd_query_string (MYSQL_THD thd);
+unsigned long long thd_query_id(const MYSQL_THD thd);
+size_t thd_query_safe(MYSQL_THD thd, char *buf, size_t buflen);
+const char *thd_user_name(MYSQL_THD thd);
+const char *thd_client_host(MYSQL_THD thd);
+const char *thd_client_ip(MYSQL_THD thd);
+LEX_CSTRING *thd_current_db(MYSQL_THD thd);
+int thd_current_status(MYSQL_THD thd);
+enum enum_server_command thd_current_command(MYSQL_THD thd);
+
+int maria_compare_hostname(const char *wild_host, long wild_ip, long ip_mask,
+ const char *host, const char *ip);
+void maria_update_hostname(const char **wild_host, long *wild_ip, long *ip_mask,
+ const char *host);
+
+/* Status variables for SHOW STATUS */
+static long test_passed= 0;
+static struct st_mysql_show_var test_sql_status[]=
+{
+ {"test_sql_service_passed", (char *)&test_passed, SHOW_LONG},
+ {0,0,0}
+};
+
+static my_bool do_test= TRUE;
+static void run_test(MYSQL_THD thd, struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save);
+static MYSQL_SYSVAR_BOOL(run_test, do_test, PLUGIN_VAR_OPCMDARG,
+ "Perform the test now.", NULL, run_test, FALSE);
+static struct st_mysql_sys_var* test_sql_vars[]=
+{
+ MYSQL_SYSVAR(run_test),
+ NULL
+};
+
+
+extern int execute_sql_command(const char *command,
+ char *hosts, char *names, char *filters);
+
+
+
+static int do_tests()
+{
+ char plugins[1024];
+ char names[1024];
+ char dl[2048];
+ int result;
+
+ result= execute_sql_command("select 'plugin', name, dl from mysql.plugin",
+ plugins, names, dl);
+
+ return result;
+}
+
+
+void auditing(MYSQL_THD thd, unsigned int event_class, const void *ev)
+{
+}
+
+
+static void run_test(MYSQL_THD thd __attribute__((unused)),
+ struct st_mysql_sys_var *var __attribute__((unused)),
+ void *var_ptr __attribute__((unused)),
+ const void *save __attribute__((unused)))
+{
+ test_passed= do_tests();
+}
+
+
+static int init_done= 0;
+
+static int test_sql_service_plugin_init(void *p __attribute__((unused)))
+{
+ init_done= 1;
+ return 0;
+}
+
+
+static int test_sql_service_plugin_deinit(void *p __attribute__((unused)))
+{
+ if (!init_done)
+ return 0;
+
+ return 0;
+}
+
+
+static struct st_mysql_audit maria_descriptor =
+{
+ MYSQL_AUDIT_INTERFACE_VERSION,
+ NULL,
+ auditing,
+ { MYSQL_AUDIT_GENERAL_CLASSMASK |
+ MYSQL_AUDIT_TABLE_CLASSMASK |
+ MYSQL_AUDIT_CONNECTION_CLASSMASK }
+};
+maria_declare_plugin(test_sql_service)
+{
+ MYSQL_AUDIT_PLUGIN,
+ &maria_descriptor,
+ "TEST_SQL_SERVICE",
+ "Alexey Botchkov (MariaDB Corporation)",
+ "Test SQL service",
+ PLUGIN_LICENSE_GPL,
+ test_sql_service_plugin_init,
+ test_sql_service_plugin_deinit,
+ PLUGIN_VERSION,
+ test_sql_status,
+ test_sql_vars,
+ PLUGIN_STR_VERSION,
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
+
diff --git a/plugin/type_geom/CMakeLists.txt b/plugin/type_geom/CMakeLists.txt
new file mode 100644
index 00000000..2b0c84f6
--- /dev/null
+++ b/plugin/type_geom/CMakeLists.txt
@@ -0,0 +1,3 @@
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql)
+
+MYSQL_ADD_PLUGIN(TYPE_GEOM plugin.cc MANDATORY RECOMPILE_FOR_EMBEDDED)
diff --git a/plugin/type_geom/plugin.cc b/plugin/type_geom/plugin.cc
new file mode 100644
index 00000000..b462a34c
--- /dev/null
+++ b/plugin/type_geom/plugin.cc
@@ -0,0 +1,254 @@
+/*
+ Copyright (c) 2000, 2015, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2019, MariaDB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#include <my_global.h>
+#include <sql_class.h> // THD
+#include <sql_i_s.h> // ST_SCHEMA_TABLE
+#include <mysql/plugin.h>
+#include "sql_show.h" // get_all_tables()
+#include "sql_error.h" // convert_error_to_warning()
+#include "sql_type_geom.h"
+
+
+/*********** INFORMATION_SCHEMA.SPATIEL_REF_SYS *******************/
+
+namespace Show {
+
+static ST_FIELD_INFO spatial_ref_sys_fields_info[]=
+{
+ Column("SRID", SShort(5), NOT_NULL),
+ Column("AUTH_NAME", Varchar(FN_REFLEN), NOT_NULL),
+ Column("AUTH_SRID", SLong(5), NOT_NULL),
+ Column("SRTEXT", Varchar(2048), NOT_NULL),
+ CEnd()
+};
+
+
+static int spatial_ref_sys_fill(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+ DBUG_ENTER("fill_spatial_ref_sys");
+ TABLE *table= tables->table;
+ CHARSET_INFO *cs= system_charset_info;
+ int result= 1;
+
+ restore_record(table, s->default_values);
+
+ table->field[0]->store(-1, FALSE); /*SRID*/
+ table->field[1]->store(STRING_WITH_LEN("Not defined"), cs); /*AUTH_NAME*/
+ table->field[2]->store(-1, FALSE); /*AUTH_SRID*/
+ table->field[3]->store(STRING_WITH_LEN(
+ "LOCAL_CS[\"Spatial reference wasn't specified\","
+ "LOCAL_DATUM[\"Unknown\",0]," "UNIT[\"m\",1.0]," "AXIS[\"x\",EAST],"
+ "AXIS[\"y\",NORTH]]"), cs);/*SRTEXT*/
+ if (schema_table_store_record(thd, table))
+ goto exit;
+
+ table->field[0]->store(0, TRUE); /*SRID*/
+ table->field[1]->store(STRING_WITH_LEN("EPSG"), cs); /*AUTH_NAME*/
+ table->field[2]->store(404000, TRUE); /*AUTH_SRID*/
+ table->field[3]->store(STRING_WITH_LEN(
+ "LOCAL_CS[\"Wildcard 2D cartesian plane in metric unit\","
+ "LOCAL_DATUM[\"Unknown\",0]," "UNIT[\"m\",1.0],"
+ "AXIS[\"x\",EAST]," "AXIS[\"y\",NORTH],"
+ "AUTHORITY[\"EPSG\",\"404000\"]]"), cs);/*SRTEXT*/
+ if (schema_table_store_record(thd, table))
+ goto exit;
+
+ result= 0;
+
+exit:
+ DBUG_RETURN(result);
+}
+
+
+static int plugin_init_spatial_ref_sys(void *p)
+{
+ ST_SCHEMA_TABLE *schema= (ST_SCHEMA_TABLE *)p;
+ schema->fields_info= spatial_ref_sys_fields_info;
+ schema->fill_table= spatial_ref_sys_fill;
+ return 0;
+}
+
+
+static struct st_mysql_information_schema spatial_ref_sys_plugin=
+{ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+
+} // namespace Show
+
+/*********** INFORMATION_SCHEMA.GEOMETRY_COLUMNS *******************/
+
+
+namespace Show {
+
+static ST_FIELD_INFO geometry_columns_fields_info[]=
+{
+ Column("F_TABLE_CATALOG", Catalog(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("F_TABLE_SCHEMA", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("F_TABLE_NAME", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("F_GEOMETRY_COLUMN", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("G_TABLE_CATALOG", Catalog(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("G_TABLE_SCHEMA", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("G_TABLE_NAME", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("G_GEOMETRY_COLUMN", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("STORAGE_TYPE", STiny(2), NOT_NULL, OPEN_FRM_ONLY),
+ Column("GEOMETRY_TYPE", SLong(7), NOT_NULL, OPEN_FRM_ONLY),
+ Column("COORD_DIMENSION", STiny(2), NOT_NULL, OPEN_FRM_ONLY),
+ Column("MAX_PPR", STiny(2), NOT_NULL, OPEN_FRM_ONLY),
+ Column("SRID", SShort(5), NOT_NULL, OPEN_FRM_ONLY),
+ CEnd()
+};
+
+
+static void geometry_columns_fill_record(TABLE *table,
+ const LEX_CSTRING *db_name,
+ const LEX_CSTRING *table_name,
+ const Field_geom *field)
+{
+ static const LEX_CSTRING catalog= {STRING_WITH_LEN("def")};
+ const CHARSET_INFO *cs= system_charset_info;
+ const Type_handler_geometry *gth= field->type_handler_geom();
+ /*F_TABLE_CATALOG*/
+ table->field[0]->store(catalog, cs);
+ /*F_TABLE_SCHEMA*/
+ table->field[1]->store(db_name, cs);
+ /*F_TABLE_NAME*/
+ table->field[2]->store(table_name, cs);
+ /*G_TABLE_CATALOG*/
+ table->field[4]->store(catalog, cs);
+ /*G_TABLE_SCHEMA*/
+ table->field[5]->store(db_name, cs);
+ /*G_TABLE_NAME*/
+ table->field[6]->store(table_name, cs);
+ /*G_GEOMETRY_COLUMN*/
+ table->field[7]->store(field->field_name, cs);
+ /*STORAGE_TYPE*/
+ table->field[8]->store(1LL, true); /*Always 1 (binary implementation)*/
+ /*GEOMETRY_TYPE*/
+ table->field[9]->store((longlong) (gth->geometry_type()), true);
+ /*COORD_DIMENSION*/
+ table->field[10]->store(2LL, true);
+ /*MAX_PPR*/
+ table->field[11]->set_null();
+ /*SRID*/
+ table->field[12]->store((longlong) (field->get_srid()), true);
+}
+
+
+static int get_geometry_column_record(THD *thd, TABLE_LIST *tables,
+ TABLE *table, bool res,
+ const LEX_CSTRING *db_name,
+ const LEX_CSTRING *table_name)
+{
+ TABLE *show_table;
+ Field **ptr, *field;
+ DBUG_ENTER("get_geometry_column_record");
+
+ if (res)
+ {
+ /*
+ open_table() failed with an error.
+ Convert the error to a warning and let the caller
+ continue with the next table.
+ */
+ convert_error_to_warning(thd);
+ DBUG_RETURN(0);
+ }
+
+ // Skip INFORMATION_SCHEMA tables. They don't have geometry columns.
+ if (tables->schema_table)
+ DBUG_RETURN(0);
+
+ show_table= tables->table;
+ ptr= show_table->field;
+ show_table->use_all_columns(); // Required for default
+ restore_record(show_table, s->default_values);
+
+ for (; (field= *ptr) ; ptr++)
+ {
+ const Field_geom *fg;
+ if (field->type() == MYSQL_TYPE_GEOMETRY &&
+ (fg= dynamic_cast<const Field_geom*>(field)))
+ {
+ DEBUG_SYNC(thd, "get_schema_column");
+ /* Get default row, with all NULL fields set to NULL */
+ restore_record(table, s->default_values);
+ geometry_columns_fill_record(table, db_name, table_name, fg);
+ if (schema_table_store_record(thd, table))
+ DBUG_RETURN(1);
+ }
+ }
+
+ DBUG_RETURN(0);
+}
+
+
+static int plugin_init_geometry_columns(void *p)
+{
+ ST_SCHEMA_TABLE *schema= (ST_SCHEMA_TABLE *)p;
+ schema->fields_info= geometry_columns_fields_info;
+ schema->fill_table= get_all_tables;
+ schema->process_table= get_geometry_column_record;
+ schema->idx_field1= 1;
+ schema->idx_field2= 2;
+ schema->i_s_requested_object= OPTIMIZE_I_S_TABLE | OPEN_VIEW_FULL;
+ return 0;
+}
+
+
+static struct st_mysql_information_schema geometry_columns_plugin=
+{ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+
+} // namespace Show
+
+
+/********************* Plugin library descriptors ************************/
+
+
+maria_declare_plugin(type_geom)
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN, // the plugin type (see include/mysql/plugin.h)
+ &Show::spatial_ref_sys_plugin, // pointer to type-specific plugin descriptor
+ "SPATIAL_REF_SYS", // plugin name
+ "MariaDB", // plugin author
+ "Lists all geometry columns", // the plugin description
+ PLUGIN_LICENSE_GPL, // the plugin license (see include/mysql/plugin.h)
+ Show::plugin_init_spatial_ref_sys, // Pointer to plugin initialization function
+ 0, // Pointer to plugin deinitialization function
+ 0x0100, // Numeric version 0xAABB means AA.BB version
+ NULL, // Status variables
+ NULL, // System variables
+ "1.0", // String version representation
+ MariaDB_PLUGIN_MATURITY_STABLE // Maturity (see include/mysql/plugin.h)*/
+},
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN, // the plugin type (see include/mysql/plugin.h)
+ &Show::geometry_columns_plugin, // pointer to type-specific plugin descriptor
+ "GEOMETRY_COLUMNS", // plugin name
+ "MariaDB", // plugin author
+ "Lists all geometry columns", // the plugin description
+ PLUGIN_LICENSE_GPL, // the plugin license (see include/mysql/plugin.h)
+ Show::plugin_init_geometry_columns,// Pointer to plugin initialization function
+ 0, // Pointer to plugin deinitialization function
+ 0x0100, // Numeric version 0xAABB means AA.BB version
+ NULL, // Status variables
+ NULL, // System variables
+ "1.0", // String version representation
+ MariaDB_PLUGIN_MATURITY_STABLE // Maturity (see include/mysql/plugin.h)
+}
+maria_declare_plugin_end;
diff --git a/plugin/type_inet/CMakeLists.txt b/plugin/type_inet/CMakeLists.txt
new file mode 100644
index 00000000..0040ceec
--- /dev/null
+++ b/plugin/type_inet/CMakeLists.txt
@@ -0,0 +1,18 @@
+# Copyright (c) 2019, MariaDB corporation.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+MYSQL_ADD_PLUGIN(type_inet
+ plugin.cc item_inetfunc.cc sql_type_inet.cc
+ MANDATORY RECOMPILE_FOR_EMBEDDED)
diff --git a/plugin/type_inet/item_inetfunc.cc b/plugin/type_inet/item_inetfunc.cc
new file mode 100644
index 00000000..50bd8281
--- /dev/null
+++ b/plugin/type_inet/item_inetfunc.cc
@@ -0,0 +1,256 @@
+/* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2014 MariaDB Foundation
+ Copyright (c) 2019 MariaDB Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#define MYSQL_SERVER
+#include "mariadb.h"
+#include "item_inetfunc.h"
+#include "sql_type_inet.h"
+
+///////////////////////////////////////////////////////////////////////////
+
+longlong Item_func_inet_aton::val_int()
+{
+ DBUG_ASSERT(fixed);
+
+ uint byte_result= 0;
+ ulonglong result= 0; // We are ready for 64 bit addresses
+ const char *p,* end;
+ char c= '.'; // we mark c to indicate invalid IP in case length is 0
+ int dot_count= 0;
+
+ StringBuffer<36> tmp;
+ String *s= args[0]->val_str_ascii(&tmp);
+
+ if (!s) // If null value
+ goto err;
+
+ null_value= 0;
+
+ end= (p = s->ptr()) + s->length();
+ while (p < end)
+ {
+ c= *p++;
+ int digit= (int) (c - '0');
+ if (digit >= 0 && digit <= 9)
+ {
+ if ((byte_result= byte_result * 10 + digit) > 255)
+ goto err; // Wrong address
+ }
+ else if (c == '.')
+ {
+ dot_count++;
+ result= (result << 8) + (ulonglong) byte_result;
+ byte_result= 0;
+ }
+ else
+ goto err; // Invalid character
+ }
+ if (c != '.') // IP number can't end on '.'
+ {
+ /*
+ Attempt to support short forms of IP-addresses. It's however pretty
+ basic one comparing to the BSD support.
+ Examples:
+ 127 -> 0.0.0.127
+ 127.255 -> 127.0.0.255
+ 127.256 -> NULL (should have been 127.0.1.0)
+ 127.2.1 -> 127.2.0.1
+ */
+ switch (dot_count) {
+ case 1: result<<= 8; /* Fall through */
+ case 2: result<<= 8; /* Fall through */
+ }
+ return (result << 8) + (ulonglong) byte_result;
+ }
+
+err:
+ null_value=1;
+ return 0;
+}
+
+
+String* Item_func_inet_ntoa::val_str(String* str)
+{
+ DBUG_ASSERT(fixed);
+
+ ulonglong n= (ulonglong) args[0]->val_int();
+
+ /*
+ We do not know if args[0] is NULL until we have called
+ some val function on it if args[0] is not a constant!
+
+ Also return null if n > 255.255.255.255
+ */
+ if ((null_value= (args[0]->null_value || n > 0xffffffff)))
+ return 0; // Null value
+
+ str->set_charset(collation.collation);
+ str->length(0);
+
+ uchar buf[8];
+ int4store(buf, n);
+
+ /* Now we can assume little endian. */
+
+ char num[4];
+ num[3]= '.';
+
+ for (uchar *p= buf + 4; p-- > buf;)
+ {
+ uint c= *p;
+ uint n1, n2; // Try to avoid divisions
+ n1= c / 100; // 100 digits
+ c-= n1 * 100;
+ n2= c / 10; // 10 digits
+ c-= n2 * 10; // last digit
+ num[0]= (char) n1 + '0';
+ num[1]= (char) n2 + '0';
+ num[2]= (char) c + '0';
+ uint length= (n1 ? 4 : n2 ? 3 : 2); // Remove pre-zero
+ uint dot_length= (p <= buf) ? 1 : 0;
+ (void) str->append(num + 4 - length, length - dot_length,
+ &my_charset_latin1);
+ }
+
+ return str;
+}
+
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+ Converts IP-address-string to IP-address-data.
+
+ ipv4-string -> varbinary(4)
+ ipv6-string -> varbinary(16)
+
+ @return Completion status.
+ @retval NULL Given string does not represent an IP-address.
+ @retval !NULL The string has been converted sucessfully.
+*/
+
+String *Item_func_inet6_aton::val_str(String *buffer)
+{
+ DBUG_ASSERT(fixed);
+
+ Ascii_ptr_and_buffer<STRING_BUFFER_USUAL_SIZE> tmp(args[0]);
+ if ((null_value= tmp.is_null()))
+ return NULL;
+
+ Inet4_null ipv4(*tmp.string());
+ if (!ipv4.is_null())
+ {
+ ipv4.to_binary(buffer);
+ return buffer;
+ }
+
+ Inet6_null ipv6(*tmp.string());
+ if (!ipv6.is_null())
+ {
+ ipv6.to_binary(buffer);
+ return buffer;
+ }
+
+ null_value= true;
+ return NULL;
+}
+
+
+/**
+ Converts IP-address-data to IP-address-string.
+*/
+
+String *Item_func_inet6_ntoa::val_str_ascii(String *buffer)
+{
+ DBUG_ASSERT(fixed);
+
+ // Binary string argument expected
+ if (unlikely(args[0]->result_type() != STRING_RESULT ||
+ args[0]->collation.collation != &my_charset_bin))
+ {
+ null_value= true;
+ return NULL;
+ }
+
+ String_ptr_and_buffer<STRING_BUFFER_USUAL_SIZE> tmp(args[0]);
+ if ((null_value= tmp.is_null()))
+ return NULL;
+
+ Inet4_null ipv4(static_cast<const Binary_string&>(*tmp.string()));
+ if (!ipv4.is_null())
+ {
+ ipv4.to_string(buffer);
+ return buffer;
+ }
+
+ Inet6_null ipv6(static_cast<const Binary_string&>(*tmp.string()));
+ if (!ipv6.is_null())
+ {
+ ipv6.to_string(buffer);
+ return buffer;
+ }
+
+ DBUG_PRINT("info", ("INET6_NTOA(): varbinary(4) or varbinary(16) expected."));
+ null_value= true;
+ return NULL;
+}
+
+
+/**
+ Checks if the passed string represents an IPv4-address.
+*/
+
+longlong Item_func_is_ipv4::val_int()
+{
+ DBUG_ASSERT(fixed);
+ String_ptr_and_buffer<STRING_BUFFER_USUAL_SIZE> tmp(args[0]);
+ return !tmp.is_null() && !Inet4_null(*tmp.string()).is_null();
+}
+
+
+/**
+ Checks if the passed string represents an IPv6-address.
+*/
+
+longlong Item_func_is_ipv6::val_int()
+{
+ DBUG_ASSERT(fixed);
+ String_ptr_and_buffer<STRING_BUFFER_USUAL_SIZE> tmp(args[0]);
+ return !tmp.is_null() && !Inet6_null(*tmp.string()).is_null();
+}
+
+
+/**
+ Checks if the passed IPv6-address is an IPv4-compat IPv6-address.
+*/
+
+longlong Item_func_is_ipv4_compat::val_int()
+{
+ Inet6_null ip6(args[0]);
+ return !ip6.is_null() && ip6.is_v4compat();
+}
+
+
+/**
+ Checks if the passed IPv6-address is an IPv4-mapped IPv6-address.
+*/
+
+longlong Item_func_is_ipv4_mapped::val_int()
+{
+ Inet6_null ip6(args[0]);
+ return !ip6.is_null() && ip6.is_v4mapped();
+}
diff --git a/plugin/type_inet/item_inetfunc.h b/plugin/type_inet/item_inetfunc.h
new file mode 100644
index 00000000..94255426
--- /dev/null
+++ b/plugin/type_inet/item_inetfunc.h
@@ -0,0 +1,227 @@
+#ifndef ITEM_INETFUNC_INCLUDED
+#define ITEM_INETFUNC_INCLUDED
+
+/* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2014 MariaDB Foundation
+ Copyright (c) 2019 MariaDB Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+
+#include "item.h"
+
+/*************************************************************************
+ Item_func_inet_aton implements INET_ATON() SQL-function.
+*************************************************************************/
+
+class Item_func_inet_aton : public Item_longlong_func
+{
+ bool check_arguments() const
+ { return check_argument_types_can_return_text(0, arg_count); }
+public:
+ Item_func_inet_aton(THD *thd, Item *a): Item_longlong_func(thd, a) {}
+ longlong val_int();
+ const char *func_name() const { return "inet_aton"; }
+ bool fix_length_and_dec()
+ {
+ decimals= 0;
+ max_length= 21;
+ maybe_null= 1;
+ unsigned_flag= 1;
+ return FALSE;
+ }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_inet_aton>(thd, this); }
+};
+
+
+/*************************************************************************
+ Item_func_inet_ntoa implements INET_NTOA() SQL-function.
+*************************************************************************/
+
+class Item_func_inet_ntoa : public Item_str_func
+{
+public:
+ Item_func_inet_ntoa(THD *thd, Item *a): Item_str_func(thd, a)
+ { }
+ String* val_str(String* str);
+ const char *func_name() const { return "inet_ntoa"; }
+ bool fix_length_and_dec()
+ {
+ decimals= 0;
+ fix_length_and_charset(3 * 8 + 7, default_charset());
+ maybe_null= 1;
+ return FALSE;
+ }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_inet_ntoa>(thd, this); }
+};
+
+
+/*************************************************************************
+ Item_func_inet_bool_base implements common code for INET6/IP-related
+ functions returning boolean value.
+*************************************************************************/
+
+class Item_func_inet_bool_base : public Item_bool_func
+{
+public:
+ inline Item_func_inet_bool_base(THD *thd, Item *ip_addr):
+ Item_bool_func(thd, ip_addr)
+ {
+ null_value= false;
+ }
+ bool need_parentheses_in_default() { return false; }
+};
+
+
+/*************************************************************************
+ Item_func_inet6_aton implements INET6_ATON() SQL-function.
+*************************************************************************/
+
+class Item_func_inet6_aton : public Item_str_func
+{
+public:
+ inline Item_func_inet6_aton(THD *thd, Item *ip_addr):
+ Item_str_func(thd, ip_addr)
+ { }
+
+public:
+ virtual const char *func_name() const
+ { return "inet6_aton"; }
+
+ virtual bool fix_length_and_dec()
+ {
+ decimals= 0;
+ fix_length_and_charset(16, &my_charset_bin);
+ maybe_null= 1;
+ return FALSE;
+ }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_inet6_aton>(thd, this); }
+
+ String *val_str(String *to);
+};
+
+
+/*************************************************************************
+ Item_func_inet6_ntoa implements INET6_NTOA() SQL-function.
+*************************************************************************/
+
+class Item_func_inet6_ntoa : public Item_str_ascii_func
+{
+public:
+ inline Item_func_inet6_ntoa(THD *thd, Item *ip_addr):
+ Item_str_ascii_func(thd, ip_addr)
+ { }
+
+public:
+ virtual const char *func_name() const
+ { return "inet6_ntoa"; }
+
+ virtual bool fix_length_and_dec()
+ {
+ decimals= 0;
+
+ // max length: IPv6-address -- 16 bytes
+ // 16 bytes / 2 bytes per group == 8 groups => 7 delimiter
+ // 4 symbols per group
+ fix_length_and_charset(8 * 4 + 7, default_charset());
+
+ maybe_null= 1;
+ return FALSE;
+ }
+ String *val_str_ascii(String *to);
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_inet6_ntoa>(thd, this); }
+};
+
+
+/*************************************************************************
+ Item_func_is_ipv4 implements IS_IPV4() SQL-function.
+*************************************************************************/
+
+class Item_func_is_ipv4 : public Item_func_inet_bool_base
+{
+public:
+ inline Item_func_is_ipv4(THD *thd, Item *ip_addr):
+ Item_func_inet_bool_base(thd, ip_addr)
+ { }
+
+public:
+ virtual const char *func_name() const
+ { return "is_ipv4"; }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_is_ipv4>(thd, this); }
+
+ longlong val_int();
+};
+
+
+/*************************************************************************
+ Item_func_is_ipv6 implements IS_IPV6() SQL-function.
+*************************************************************************/
+
+class Item_func_is_ipv6 : public Item_func_inet_bool_base
+{
+public:
+ inline Item_func_is_ipv6(THD *thd, Item *ip_addr):
+ Item_func_inet_bool_base(thd, ip_addr)
+ { }
+
+ virtual const char *func_name() const
+ { return "is_ipv6"; }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_is_ipv6>(thd, this); }
+
+ longlong val_int();
+};
+
+
+/*************************************************************************
+ Item_func_is_ipv4_compat implements IS_IPV4_COMPAT() SQL-function.
+*************************************************************************/
+
+class Item_func_is_ipv4_compat : public Item_func_inet_bool_base
+{
+public:
+ inline Item_func_is_ipv4_compat(THD *thd, Item *ip_addr):
+ Item_func_inet_bool_base(thd, ip_addr)
+ { }
+ virtual const char *func_name() const
+ { return "is_ipv4_compat"; }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_is_ipv4_compat>(thd, this); }
+ longlong val_int();
+};
+
+
+/*************************************************************************
+ Item_func_is_ipv4_mapped implements IS_IPV4_MAPPED() SQL-function.
+*************************************************************************/
+
+class Item_func_is_ipv4_mapped : public Item_func_inet_bool_base
+{
+public:
+ inline Item_func_is_ipv4_mapped(THD *thd, Item *ip_addr):
+ Item_func_inet_bool_base(thd, ip_addr)
+ { }
+ virtual const char *func_name() const
+ { return "is_ipv4_mapped"; }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_is_ipv4_mapped>(thd, this); }
+ longlong val_int();
+};
+
+#endif // ITEM_INETFUNC_INCLUDED
diff --git a/plugin/type_inet/mysql-test/type_inet/binlog_stm_type_inet6.result b/plugin/type_inet/mysql-test/type_inet/binlog_stm_type_inet6.result
new file mode 100644
index 00000000..e09b1021
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/binlog_stm_type_inet6.result
@@ -0,0 +1,34 @@
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('::');
+INSERT INTO t1 VALUES ('ffff::ffff');
+PREPARE stmt FROM 'INSERT INTO t1 VALUES (?)';
+EXECUTE stmt USING CAST('::1' AS INET6);
+EXECUTE stmt USING CAST(CONCAT(REPEAT(0x00,15), 0x02) AS INET6);
+DEALLOCATE PREPARE stmt;
+BEGIN NOT ATOMIC
+DECLARE a INET6 DEFAULT '::3';
+INSERT INTO t1 VALUES (a);
+END;
+$$
+DROP TABLE t1;
+include/show_binlog_events.inc
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Gtid # # GTID #-#-#
+master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INET6)
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES ('::')
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES ('ffff::ffff')
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES ('::1')
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES ('::2')
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # BEGIN GTID #-#-#
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES ( NAME_CONST('a','::3'))
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Gtid # # GTID #-#-#
+master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */
diff --git a/plugin/type_inet/mysql-test/type_inet/binlog_stm_type_inet6.test b/plugin/type_inet/mysql-test/type_inet/binlog_stm_type_inet6.test
new file mode 100644
index 00000000..d5144809
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/binlog_stm_type_inet6.test
@@ -0,0 +1,28 @@
+--source include/not_embedded.inc
+--source include/have_binlog_format_statement.inc
+
+--disable_query_log
+reset master; # get rid of previous tests binlog
+--enable_query_log
+
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('::');
+INSERT INTO t1 VALUES ('ffff::ffff');
+
+PREPARE stmt FROM 'INSERT INTO t1 VALUES (?)';
+EXECUTE stmt USING CAST('::1' AS INET6);
+EXECUTE stmt USING CAST(CONCAT(REPEAT(0x00,15), 0x02) AS INET6);
+DEALLOCATE PREPARE stmt;
+
+DELIMITER $$;
+BEGIN NOT ATOMIC
+ DECLARE a INET6 DEFAULT '::3';
+ INSERT INTO t1 VALUES (a);
+END;
+$$
+DELIMITER ;$$
+
+DROP TABLE t1;
+
+--let $binlog_file = LAST
+source include/show_binlog_events.inc;
diff --git a/plugin/type_inet/mysql-test/type_inet/binlog_table_map_optional_metadata_type_inet6.result b/plugin/type_inet/mysql-test/type_inet/binlog_table_map_optional_metadata_type_inet6.result
new file mode 100644
index 00000000..7911407b
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/binlog_table_map_optional_metadata_type_inet6.result
@@ -0,0 +1,60 @@
+#
+# Start of 10.5 tests
+#
+#
+# MDEV-20822 INET6 crashes in combination with RBR extended metadata
+#
+# Using DEFAULT_CHARSET format
+RESET MASTER;
+SET GLOBAL binlog_row_metadata = NO_LOG;
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES('::');
+# Columns(BINARY(16))
+DROP TABLE t1;
+RESET MASTER;
+RESET MASTER;
+SET GLOBAL binlog_row_metadata = MINIMAL;
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES('::');
+# Columns(BINARY(16))
+DROP TABLE t1;
+RESET MASTER;
+RESET MASTER;
+SET GLOBAL binlog_row_metadata = FULL;
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES('::');
+# Columns(`a` BINARY(16))
+DROP TABLE t1;
+RESET MASTER;
+# Using COLUMN_CHARSET format
+RESET MASTER;
+SET GLOBAL binlog_row_metadata = NO_LOG;
+CREATE TABLE t1 (a INET6, b CHAR(16) CHARACTER SET latin1, c CHAR(16) CHARACTER SET utf8);
+INSERT INTO t1 VALUES('::','','');
+# Columns(BINARY(16),
+# BINARY(16),
+# BINARY(48))
+DROP TABLE t1;
+RESET MASTER;
+RESET MASTER;
+SET GLOBAL binlog_row_metadata = MINIMAL;
+CREATE TABLE t1 (a INET6, b CHAR(16) CHARACTER SET latin1, c CHAR(16) CHARACTER SET utf8);
+INSERT INTO t1 VALUES('::','','');
+# Columns(BINARY(16),
+# CHAR(16) CHARSET latin1 COLLATE latin1_swedish_ci,
+# CHAR(16) CHARSET utf8 COLLATE utf8_general_ci)
+DROP TABLE t1;
+RESET MASTER;
+RESET MASTER;
+SET GLOBAL binlog_row_metadata = FULL;
+CREATE TABLE t1 (a INET6, b CHAR(16) CHARACTER SET latin1, c CHAR(16) CHARACTER SET utf8);
+INSERT INTO t1 VALUES('::','','');
+# Columns(`a` BINARY(16),
+# `b` CHAR(16) CHARSET latin1 COLLATE latin1_swedish_ci,
+# `c` CHAR(16) CHARSET utf8 COLLATE utf8_general_ci)
+DROP TABLE t1;
+RESET MASTER;
+SET GLOBAL binlog_row_metadata = DEFAULT;
+#
+# End of 10.5 tests
+#
diff --git a/plugin/type_inet/mysql-test/type_inet/binlog_table_map_optional_metadata_type_inet6.test b/plugin/type_inet/mysql-test/type_inet/binlog_table_map_optional_metadata_type_inet6.test
new file mode 100644
index 00000000..63672f06
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/binlog_table_map_optional_metadata_type_inet6.test
@@ -0,0 +1,72 @@
+--source include/have_debug.inc
+--source include/have_binlog_format_row.inc
+
+--let $MYSQLD_DATADIR= `select @@datadir`
+--let $binlog_file= $MYSQLD_DATADIR/master-bin.000001
+
+
+--echo #
+--echo # Start of 10.5 tests
+--echo #
+
+--echo #
+--echo # MDEV-20822 INET6 crashes in combination with RBR extended metadata
+--echo #
+
+--echo # Using DEFAULT_CHARSET format
+
+RESET MASTER;
+SET GLOBAL binlog_row_metadata = NO_LOG;
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES('::');
+--source suite/binlog/include/print_optional_metadata.inc
+DROP TABLE t1;
+RESET MASTER;
+
+RESET MASTER;
+SET GLOBAL binlog_row_metadata = MINIMAL;
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES('::');
+--source suite/binlog/include/print_optional_metadata.inc
+DROP TABLE t1;
+RESET MASTER;
+
+RESET MASTER;
+SET GLOBAL binlog_row_metadata = FULL;
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES('::');
+--source suite/binlog/include/print_optional_metadata.inc
+DROP TABLE t1;
+RESET MASTER;
+
+--echo # Using COLUMN_CHARSET format
+
+RESET MASTER;
+SET GLOBAL binlog_row_metadata = NO_LOG;
+CREATE TABLE t1 (a INET6, b CHAR(16) CHARACTER SET latin1, c CHAR(16) CHARACTER SET utf8);
+INSERT INTO t1 VALUES('::','','');
+--source suite/binlog/include/print_optional_metadata.inc
+DROP TABLE t1;
+RESET MASTER;
+
+RESET MASTER;
+SET GLOBAL binlog_row_metadata = MINIMAL;
+CREATE TABLE t1 (a INET6, b CHAR(16) CHARACTER SET latin1, c CHAR(16) CHARACTER SET utf8);
+INSERT INTO t1 VALUES('::','','');
+--source suite/binlog/include/print_optional_metadata.inc
+DROP TABLE t1;
+RESET MASTER;
+
+RESET MASTER;
+SET GLOBAL binlog_row_metadata = FULL;
+CREATE TABLE t1 (a INET6, b CHAR(16) CHARACTER SET latin1, c CHAR(16) CHARACTER SET utf8);
+INSERT INTO t1 VALUES('::','','');
+--source suite/binlog/include/print_optional_metadata.inc
+DROP TABLE t1;
+RESET MASTER;
+
+SET GLOBAL binlog_row_metadata = DEFAULT;
+
+--echo #
+--echo # End of 10.5 tests
+--echo #
diff --git a/plugin/type_inet/mysql-test/type_inet/func_inet_plugin.result b/plugin/type_inet/mysql-test/type_inet/func_inet_plugin.result
new file mode 100644
index 00000000..9ee1a020
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/func_inet_plugin.result
@@ -0,0 +1,112 @@
+#
+# Start of 10.5 tests
+#
+#
+# MDEV-20768 Turn INET functions into a function collection plugin
+#
+SELECT
+'----' AS `----`,
+PLUGIN_NAME,
+PLUGIN_VERSION,
+PLUGIN_STATUS,
+PLUGIN_TYPE,
+PLUGIN_AUTHOR,
+PLUGIN_DESCRIPTION,
+PLUGIN_LICENSE,
+PLUGIN_MATURITY,
+PLUGIN_AUTH_VERSION
+FROM INFORMATION_SCHEMA.PLUGINS
+WHERE PLUGIN_TYPE='FUNCTION'
+ AND PLUGIN_NAME IN
+('inet_aton',
+'inet_ntoa',
+'inet6_aton',
+'inet6_ntoa',
+'is_ipv4',
+'is_ipv6',
+'is_ipv4_compat',
+'is_ipv4_mapped')
+ORDER BY PLUGIN_NAME;
+---- ----
+PLUGIN_NAME inet6_aton
+PLUGIN_VERSION 1.0
+PLUGIN_STATUS ACTIVE
+PLUGIN_TYPE FUNCTION
+PLUGIN_AUTHOR MariaDB Corporation
+PLUGIN_DESCRIPTION Function INET6_ATON()
+PLUGIN_LICENSE GPL
+PLUGIN_MATURITY Stable
+PLUGIN_AUTH_VERSION 1.0
+---- ----
+PLUGIN_NAME inet6_ntoa
+PLUGIN_VERSION 1.0
+PLUGIN_STATUS ACTIVE
+PLUGIN_TYPE FUNCTION
+PLUGIN_AUTHOR MariaDB Corporation
+PLUGIN_DESCRIPTION Function INET6_NTOA()
+PLUGIN_LICENSE GPL
+PLUGIN_MATURITY Stable
+PLUGIN_AUTH_VERSION 1.0
+---- ----
+PLUGIN_NAME inet_aton
+PLUGIN_VERSION 1.0
+PLUGIN_STATUS ACTIVE
+PLUGIN_TYPE FUNCTION
+PLUGIN_AUTHOR MariaDB Corporation
+PLUGIN_DESCRIPTION Function INET_ATON()
+PLUGIN_LICENSE GPL
+PLUGIN_MATURITY Stable
+PLUGIN_AUTH_VERSION 1.0
+---- ----
+PLUGIN_NAME inet_ntoa
+PLUGIN_VERSION 1.0
+PLUGIN_STATUS ACTIVE
+PLUGIN_TYPE FUNCTION
+PLUGIN_AUTHOR MariaDB Corporation
+PLUGIN_DESCRIPTION Function INET_NTOA()
+PLUGIN_LICENSE GPL
+PLUGIN_MATURITY Stable
+PLUGIN_AUTH_VERSION 1.0
+---- ----
+PLUGIN_NAME is_ipv4
+PLUGIN_VERSION 1.0
+PLUGIN_STATUS ACTIVE
+PLUGIN_TYPE FUNCTION
+PLUGIN_AUTHOR MariaDB Corporation
+PLUGIN_DESCRIPTION Function IS_IPV4()
+PLUGIN_LICENSE GPL
+PLUGIN_MATURITY Stable
+PLUGIN_AUTH_VERSION 1.0
+---- ----
+PLUGIN_NAME is_ipv4_compat
+PLUGIN_VERSION 1.0
+PLUGIN_STATUS ACTIVE
+PLUGIN_TYPE FUNCTION
+PLUGIN_AUTHOR MariaDB Corporation
+PLUGIN_DESCRIPTION Function IS_IPV4_COMPAT()
+PLUGIN_LICENSE GPL
+PLUGIN_MATURITY Stable
+PLUGIN_AUTH_VERSION 1.0
+---- ----
+PLUGIN_NAME is_ipv4_mapped
+PLUGIN_VERSION 1.0
+PLUGIN_STATUS ACTIVE
+PLUGIN_TYPE FUNCTION
+PLUGIN_AUTHOR MariaDB Corporation
+PLUGIN_DESCRIPTION Function IS_IPV4_MAPPED()
+PLUGIN_LICENSE GPL
+PLUGIN_MATURITY Stable
+PLUGIN_AUTH_VERSION 1.0
+---- ----
+PLUGIN_NAME is_ipv6
+PLUGIN_VERSION 1.0
+PLUGIN_STATUS ACTIVE
+PLUGIN_TYPE FUNCTION
+PLUGIN_AUTHOR MariaDB Corporation
+PLUGIN_DESCRIPTION Function IS_IPV6()
+PLUGIN_LICENSE GPL
+PLUGIN_MATURITY Stable
+PLUGIN_AUTH_VERSION 1.0
+#
+# End of 10.5 tests
+#
diff --git a/plugin/type_inet/mysql-test/type_inet/func_inet_plugin.test b/plugin/type_inet/mysql-test/type_inet/func_inet_plugin.test
new file mode 100644
index 00000000..45b462e8
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/func_inet_plugin.test
@@ -0,0 +1,37 @@
+--echo #
+--echo # Start of 10.5 tests
+--echo #
+
+--echo #
+--echo # MDEV-20768 Turn INET functions into a function collection plugin
+--echo #
+
+--vertical_results
+SELECT
+ '----' AS `----`,
+ PLUGIN_NAME,
+ PLUGIN_VERSION,
+ PLUGIN_STATUS,
+ PLUGIN_TYPE,
+ PLUGIN_AUTHOR,
+ PLUGIN_DESCRIPTION,
+ PLUGIN_LICENSE,
+ PLUGIN_MATURITY,
+ PLUGIN_AUTH_VERSION
+FROM INFORMATION_SCHEMA.PLUGINS
+WHERE PLUGIN_TYPE='FUNCTION'
+ AND PLUGIN_NAME IN
+ ('inet_aton',
+ 'inet_ntoa',
+ 'inet6_aton',
+ 'inet6_ntoa',
+ 'is_ipv4',
+ 'is_ipv6',
+ 'is_ipv4_compat',
+ 'is_ipv4_mapped')
+ORDER BY PLUGIN_NAME;
+--horizontal_results
+
+--echo #
+--echo # End of 10.5 tests
+--echo #
diff --git a/plugin/type_inet/mysql-test/type_inet/rpl_row_binary_to_inet6.result b/plugin/type_inet/mysql-test/type_inet/rpl_row_binary_to_inet6.result
new file mode 100644
index 00000000..7b69217f
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/rpl_row_binary_to_inet6.result
@@ -0,0 +1,35 @@
+include/master-slave.inc
+[connection master]
+#
+# Start of 10.5 tests
+#
+#
+# MDEV-20844 RBR from binary(16) to inet6 fails with error 171: The event was corrupt, leading to illegal data being read
+#
+CREATE TABLE t1 (a BINARY(16));
+connection slave;
+ALTER TABLE t1 MODIFY a INET6;
+connection master;
+INSERT INTO t1 VALUES (INET6_ATON('::'));
+INSERT INTO t1 VALUES (INET6_ATON('::192.168.0.1'));
+INSERT INTO t1 VALUES (INET6_ATON('ffff::'));
+INSERT INTO t1 VALUES (INET6_ATON('ffff::192.168.0.1'));
+SELECT INET6_NTOA(a) FROM t1 ORDER BY a;
+INET6_NTOA(a)
+::
+::192.168.0.1
+ffff::
+ffff::c0a8:1
+connection slave;
+SELECT * FROM t1 ORDER BY a;
+a
+::
+::192.168.0.1
+ffff::
+ffff::c0a8:1
+connection master;
+DROP TABLE t1;
+#
+# End of 10.5 tests
+#
+include/rpl_end.inc
diff --git a/plugin/type_inet/mysql-test/type_inet/rpl_row_binary_to_inet6.test b/plugin/type_inet/mysql-test/type_inet/rpl_row_binary_to_inet6.test
new file mode 100644
index 00000000..f48b1c49
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/rpl_row_binary_to_inet6.test
@@ -0,0 +1,33 @@
+--source include/have_binlog_format_row.inc
+--source include/master-slave.inc
+
+--echo #
+--echo # Start of 10.5 tests
+--echo #
+
+--echo #
+--echo # MDEV-20844 RBR from binary(16) to inet6 fails with error 171: The event was corrupt, leading to illegal data being read
+--echo #
+
+CREATE TABLE t1 (a BINARY(16));
+
+--sync_slave_with_master
+ALTER TABLE t1 MODIFY a INET6;
+
+--connection master
+INSERT INTO t1 VALUES (INET6_ATON('::'));
+INSERT INTO t1 VALUES (INET6_ATON('::192.168.0.1'));
+INSERT INTO t1 VALUES (INET6_ATON('ffff::'));
+INSERT INTO t1 VALUES (INET6_ATON('ffff::192.168.0.1'));
+SELECT INET6_NTOA(a) FROM t1 ORDER BY a;
+--sync_slave_with_master
+SELECT * FROM t1 ORDER BY a;
+
+--connection master
+DROP TABLE t1;
+
+--echo #
+--echo # End of 10.5 tests
+--echo #
+
+--source include/rpl_end.inc
diff --git a/plugin/type_inet/mysql-test/type_inet/rpl_row_inet6_to_binary.result b/plugin/type_inet/mysql-test/type_inet/rpl_row_inet6_to_binary.result
new file mode 100644
index 00000000..932043a9
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/rpl_row_inet6_to_binary.result
@@ -0,0 +1,35 @@
+include/master-slave.inc
+[connection master]
+#
+# Start of 10.5 tests
+#
+#
+# MDEV-20844 RBR from binary(16) to inet6 fails with error 171: The event was corrupt, leading to illegal data being read
+#
+CREATE TABLE t1 (a INET6);
+connection slave;
+ALTER TABLE t1 MODIFY a BINARY(16);
+connection master;
+INSERT INTO t1 VALUES ('::');
+INSERT INTO t1 VALUES ('::192.168.0.1');
+INSERT INTO t1 VALUES ('ffff::');
+INSERT INTO t1 VALUES ('ffff::192.168.0.1');
+SELECT a FROM t1 ORDER BY a;
+a
+::
+::192.168.0.1
+ffff::
+ffff::c0a8:1
+connection slave;
+SELECT INET6_NTOA(a) FROM t1 ORDER BY a;
+INET6_NTOA(a)
+::
+::192.168.0.1
+ffff::
+ffff::c0a8:1
+connection master;
+DROP TABLE t1;
+#
+# End of 10.5 tests
+#
+include/rpl_end.inc
diff --git a/plugin/type_inet/mysql-test/type_inet/rpl_row_inet6_to_binary.test b/plugin/type_inet/mysql-test/type_inet/rpl_row_inet6_to_binary.test
new file mode 100644
index 00000000..7abb4f6f
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/rpl_row_inet6_to_binary.test
@@ -0,0 +1,33 @@
+--source include/have_binlog_format_row.inc
+--source include/master-slave.inc
+
+--echo #
+--echo # Start of 10.5 tests
+--echo #
+
+--echo #
+--echo # MDEV-20844 RBR from binary(16) to inet6 fails with error 171: The event was corrupt, leading to illegal data being read
+--echo #
+
+CREATE TABLE t1 (a INET6);
+
+--sync_slave_with_master
+ALTER TABLE t1 MODIFY a BINARY(16);
+
+--connection master
+INSERT INTO t1 VALUES ('::');
+INSERT INTO t1 VALUES ('::192.168.0.1');
+INSERT INTO t1 VALUES ('ffff::');
+INSERT INTO t1 VALUES ('ffff::192.168.0.1');
+SELECT a FROM t1 ORDER BY a;
+--sync_slave_with_master
+SELECT INET6_NTOA(a) FROM t1 ORDER BY a;
+
+--connection master
+DROP TABLE t1;
+
+--echo #
+--echo # End of 10.5 tests
+--echo #
+
+--source include/rpl_end.inc
diff --git a/plugin/type_inet/mysql-test/type_inet/rpl_type_inet6.result b/plugin/type_inet/mysql-test/type_inet/rpl_type_inet6.result
new file mode 100644
index 00000000..5bda0b07
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/rpl_type_inet6.result
@@ -0,0 +1,17 @@
+include/master-slave.inc
+[connection master]
+#
+# MDEV-274 The data type for IPv6/IPv4 addresses in MariaDB
+#
+connection master;
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('::'),('ffff::ffff');
+connection slave;
+SELECT HEX(a), a FROM t1;
+HEX(a) a
+00000000000000000000000000000000 ::
+FFFF000000000000000000000000FFFF ffff::ffff
+connection master;
+DROP TABLE t1;
+connection slave;
+include/rpl_end.inc
diff --git a/plugin/type_inet/mysql-test/type_inet/rpl_type_inet6.test b/plugin/type_inet/mysql-test/type_inet/rpl_type_inet6.test
new file mode 100644
index 00000000..91c092b6
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/rpl_type_inet6.test
@@ -0,0 +1,16 @@
+--source include/master-slave.inc
+
+--echo #
+--echo # MDEV-274 The data type for IPv6/IPv4 addresses in MariaDB
+--echo #
+
+connection master;
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('::'),('ffff::ffff');
+sync_slave_with_master;
+SELECT HEX(a), a FROM t1;
+connection master;
+DROP TABLE t1;
+sync_slave_with_master;
+
+--source include/rpl_end.inc
diff --git a/plugin/type_inet/mysql-test/type_inet/suite.pm b/plugin/type_inet/mysql-test/type_inet/suite.pm
new file mode 100644
index 00000000..5893fcb7
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/suite.pm
@@ -0,0 +1,9 @@
+package My::Suite::Type_inet;
+
+@ISA = qw(My::Suite);
+
+#return "No inet6 plugin" unless $::mysqld_variables{'inet6'} eq "ON";
+
+sub is_default { 1 }
+
+bless { };
diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6-debug.result b/plugin/type_inet/mysql-test/type_inet/type_inet6-debug.result
new file mode 100644
index 00000000..0e879aad
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/type_inet6-debug.result
@@ -0,0 +1,18 @@
+#
+# MDEV-274 The data type for IPv6/IPv4 addresses in MariaDB
+#
+SET @old_debug_dbug=@@debug_dbug;
+SET debug_dbug="+d,frm_data_type_info";
+CREATE TABLE t1 (c01 INET6, c02 INET6);
+Warnings:
+Note 1105 build_frm_image: Field data type info length: 14
+Note 1105 DBUG: [0] name='c01' type_info='inet6'
+Note 1105 DBUG: [1] name='c02' type_info='inet6'
+SET debug_dbug=@old_debug_dbug;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c01` inet6 DEFAULT NULL,
+ `c02` inet6 DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6-debug.test b/plugin/type_inet/mysql-test/type_inet/type_inet6-debug.test
new file mode 100644
index 00000000..ef5ea836
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/type_inet6-debug.test
@@ -0,0 +1,14 @@
+--source include/have_debug.inc
+
+--echo #
+--echo # MDEV-274 The data type for IPv6/IPv4 addresses in MariaDB
+--echo #
+
+SET @old_debug_dbug=@@debug_dbug;
+
+SET debug_dbug="+d,frm_data_type_info";
+CREATE TABLE t1 (c01 INET6, c02 INET6);
+SET debug_dbug=@old_debug_dbug;
+
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6.result b/plugin/type_inet/mysql-test/type_inet/type_inet6.result
new file mode 100644
index 00000000..da949481
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/type_inet6.result
@@ -0,0 +1,2161 @@
+#
+# Basic CREATE functionality, defaults, metadata
+#
+CREATE TABLE t1 (a INET6 AUTO_INCREMENT);
+ERROR 42000: Incorrect column specifier for column 'a'
+CREATE TABLE t1 (a INET6);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` inet6 DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DESCRIBE t1;
+Field Type Null Key Default Extra
+a inet6 YES NULL
+SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema='test' AND table_name='t1';
+TABLE_CATALOG def
+TABLE_SCHEMA test
+TABLE_NAME t1
+COLUMN_NAME a
+ORDINAL_POSITION 1
+COLUMN_DEFAULT NULL
+IS_NULLABLE YES
+DATA_TYPE inet6
+CHARACTER_MAXIMUM_LENGTH NULL
+CHARACTER_OCTET_LENGTH NULL
+NUMERIC_PRECISION NULL
+NUMERIC_SCALE NULL
+DATETIME_PRECISION NULL
+CHARACTER_SET_NAME NULL
+COLLATION_NAME NULL
+COLUMN_TYPE inet6
+COLUMN_KEY
+EXTRA
+PRIVILEGES #
+COLUMN_COMMENT
+IS_GENERATED NEVER
+GENERATION_EXPRESSION NULL
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('::1');
+SELECT * FROM t1;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def test t1 t1 a a 254 (type=inet6) 39 3 Y 160 0 8
+a
+::1
+SELECT CAST('::' AS INET6) AS a;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def a 254 (type=inet6) 39 2 N 33 0 8
+a
+::
+DROP TABLE t1;
+CREATE TABLE t1 (
+c1 INET6 DEFAULT 0x00000000000000000000000000000000,
+c2 INET6 DEFAULT 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,
+c3 INET6 DEFAULT '::',
+c4 INET6 DEFAULT 'FFFF::ffff',
+c5 INET6 DEFAULT CAST(X'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' AS INET6)
+);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` inet6 DEFAULT '::',
+ `c2` inet6 DEFAULT 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
+ `c3` inet6 DEFAULT '::',
+ `c4` inet6 DEFAULT 'ffff::ffff',
+ `c5` inet6 DEFAULT cast(X'ffffffffffffffffffffffffffffffff' as inet6)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DESCRIBE t1;
+Field Type Null Key Default Extra
+c1 inet6 YES ::
+c2 inet6 YES ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
+c3 inet6 YES ::
+c4 inet6 YES ffff::ffff
+c5 inet6 YES cast(X'ffffffffffffffffffffffffffffffff' as inet6)
+SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema='test' AND table_name='t1';
+TABLE_CATALOG def
+TABLE_SCHEMA test
+TABLE_NAME t1
+COLUMN_NAME c1
+ORDINAL_POSITION 1
+COLUMN_DEFAULT '::'
+IS_NULLABLE YES
+DATA_TYPE inet6
+CHARACTER_MAXIMUM_LENGTH NULL
+CHARACTER_OCTET_LENGTH NULL
+NUMERIC_PRECISION NULL
+NUMERIC_SCALE NULL
+DATETIME_PRECISION NULL
+CHARACTER_SET_NAME NULL
+COLLATION_NAME NULL
+COLUMN_TYPE inet6
+COLUMN_KEY
+EXTRA
+PRIVILEGES #
+COLUMN_COMMENT
+IS_GENERATED NEVER
+GENERATION_EXPRESSION NULL
+TABLE_CATALOG def
+TABLE_SCHEMA test
+TABLE_NAME t1
+COLUMN_NAME c2
+ORDINAL_POSITION 2
+COLUMN_DEFAULT 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'
+IS_NULLABLE YES
+DATA_TYPE inet6
+CHARACTER_MAXIMUM_LENGTH NULL
+CHARACTER_OCTET_LENGTH NULL
+NUMERIC_PRECISION NULL
+NUMERIC_SCALE NULL
+DATETIME_PRECISION NULL
+CHARACTER_SET_NAME NULL
+COLLATION_NAME NULL
+COLUMN_TYPE inet6
+COLUMN_KEY
+EXTRA
+PRIVILEGES #
+COLUMN_COMMENT
+IS_GENERATED NEVER
+GENERATION_EXPRESSION NULL
+TABLE_CATALOG def
+TABLE_SCHEMA test
+TABLE_NAME t1
+COLUMN_NAME c3
+ORDINAL_POSITION 3
+COLUMN_DEFAULT '::'
+IS_NULLABLE YES
+DATA_TYPE inet6
+CHARACTER_MAXIMUM_LENGTH NULL
+CHARACTER_OCTET_LENGTH NULL
+NUMERIC_PRECISION NULL
+NUMERIC_SCALE NULL
+DATETIME_PRECISION NULL
+CHARACTER_SET_NAME NULL
+COLLATION_NAME NULL
+COLUMN_TYPE inet6
+COLUMN_KEY
+EXTRA
+PRIVILEGES #
+COLUMN_COMMENT
+IS_GENERATED NEVER
+GENERATION_EXPRESSION NULL
+TABLE_CATALOG def
+TABLE_SCHEMA test
+TABLE_NAME t1
+COLUMN_NAME c4
+ORDINAL_POSITION 4
+COLUMN_DEFAULT 'ffff::ffff'
+IS_NULLABLE YES
+DATA_TYPE inet6
+CHARACTER_MAXIMUM_LENGTH NULL
+CHARACTER_OCTET_LENGTH NULL
+NUMERIC_PRECISION NULL
+NUMERIC_SCALE NULL
+DATETIME_PRECISION NULL
+CHARACTER_SET_NAME NULL
+COLLATION_NAME NULL
+COLUMN_TYPE inet6
+COLUMN_KEY
+EXTRA
+PRIVILEGES #
+COLUMN_COMMENT
+IS_GENERATED NEVER
+GENERATION_EXPRESSION NULL
+TABLE_CATALOG def
+TABLE_SCHEMA test
+TABLE_NAME t1
+COLUMN_NAME c5
+ORDINAL_POSITION 5
+COLUMN_DEFAULT cast(X'ffffffffffffffffffffffffffffffff' as inet6)
+IS_NULLABLE YES
+DATA_TYPE inet6
+CHARACTER_MAXIMUM_LENGTH NULL
+CHARACTER_OCTET_LENGTH NULL
+NUMERIC_PRECISION NULL
+NUMERIC_SCALE NULL
+DATETIME_PRECISION NULL
+CHARACTER_SET_NAME NULL
+COLLATION_NAME NULL
+COLUMN_TYPE inet6
+COLUMN_KEY
+EXTRA
+PRIVILEGES #
+COLUMN_COMMENT
+IS_GENERATED NEVER
+GENERATION_EXPRESSION NULL
+DROP TABLE t1;
+CREATE TABLE t1 (c1 INET6 DEFAULT 0x00);
+ERROR 42000: Invalid default value for 'c1'
+CREATE TABLE t1 (c1 INET6 DEFAULT '');
+ERROR 42000: Invalid default value for 'c1'
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('x');
+ERROR 22007: Incorrect inet6 value: 'x' for column `test`.`t1`.`a` at row 1
+INSERT INTO t1 VALUES (1);
+ERROR 22007: Incorrect inet6 value: '1' for column `test`.`t1`.`a` at row 1
+INSERT INTO t1 VALUES (TIME'10:20:30');
+ERROR 22007: Incorrect inet6 value: '10:20:30' for column `test`.`t1`.`a` at row 1
+INSERT INTO t1 VALUES (0x00);
+ERROR 22007: Incorrect inet6 value: '\x00' for column `test`.`t1`.`a` at row 1
+DROP TABLE t1;
+#
+# CAST
+#
+SELECT CAST('garbage' AS INET6);
+CAST('garbage' AS INET6)
+NULL
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage'
+SELECT CAST(0x01 AS INET6);
+CAST(0x01 AS INET6)
+NULL
+Warnings:
+Warning 1292 Incorrect inet6 value: '\x01'
+SELECT CAST(REPEAT(0x00,16) AS INET6);
+CAST(REPEAT(0x00,16) AS INET6)
+::
+SELECT CAST(REPEAT(0x11,16) AS INET6);
+CAST(REPEAT(0x11,16) AS INET6)
+1111:1111:1111:1111:1111:1111:1111:1111
+CREATE TABLE t1 AS SELECT CAST('::' AS INET6);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `CAST('::' AS INET6)` inet6 NOT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+#
+# Text and binary formats, comparison operators
+#
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES (0x00000000000000000000000000000000);
+INSERT INTO t1 VALUES (0x00000000000000000000000000000001);
+INSERT INTO t1 VALUES (0xFFFF0000000000000000000000000001);
+INSERT INTO t1 VALUES (0xFFFF0000000000000000000000000002);
+SELECT * FROM t1 ORDER BY a;
+a
+::
+::1
+ffff::1
+ffff::2
+SELECT * FROM t1 ORDER BY a DESC;
+a
+ffff::2
+ffff::1
+::1
+::
+SELECT HEX(a),a FROM t1 ORDER BY a;
+HEX(a) a
+00000000000000000000000000000000 ::
+00000000000000000000000000000001 ::1
+FFFF0000000000000000000000000001 ffff::1
+FFFF0000000000000000000000000002 ffff::2
+SELECT * FROM t1 WHERE a='::';
+a
+::
+SELECT * FROM t1 WHERE a='::1';
+a
+::1
+SELECT * FROM t1 WHERE a='ffff::1';
+a
+ffff::1
+SELECT * FROM t1 WHERE a='ffff::2';
+a
+ffff::2
+SELECT * FROM t1 WHERE a=0x00000000000000000000000000000000;
+a
+::
+SELECT * FROM t1 WHERE a=0x00000000000000000000000000000001;
+a
+::1
+SELECT * FROM t1 WHERE a=0xffff0000000000000000000000000001;
+a
+ffff::1
+SELECT * FROM t1 WHERE a=0xffff0000000000000000000000000002;
+a
+ffff::2
+SELECT * FROM t1 WHERE a<'::';
+a
+SELECT * FROM t1 WHERE a<='::';
+a
+::
+SELECT * FROM t1 WHERE a>='ffff::2';
+a
+ffff::2
+SELECT * FROM t1 WHERE a>'ffff::2';
+a
+SELECT * FROM t1 WHERE a IN ('::', 'ffff::1') ORDER BY a;
+a
+::
+ffff::1
+SELECT * FROM t1 WHERE a IN ('::', 0xffff0000000000000000000000000002) ORDER BY a;
+a
+::
+ffff::2
+SELECT * FROM t1 WHERE a<'garbage';
+a
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage'
+SELECT * FROM t1 WHERE a<='garbage';
+a
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage'
+SELECT * FROM t1 WHERE a='garbage';
+a
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+SELECT * FROM t1 WHERE a>='garbage';
+a
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage'
+SELECT * FROM t1 WHERE a>'garbage';
+a
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage'
+SELECT * FROM t1 WHERE a<0x01;
+a
+Warnings:
+Warning 1292 Incorrect inet6 value: '\x01'
+SELECT * FROM t1 WHERE a<=0x01;
+a
+Warnings:
+Warning 1292 Incorrect inet6 value: '\x01'
+SELECT * FROM t1 WHERE a=0x01;
+a
+Warnings:
+Warning 1292 Incorrect inet6 value: '\x01'
+Warning 1292 Incorrect inet6 value: '\x01'
+SELECT * FROM t1 WHERE a>=0x01;
+a
+Warnings:
+Warning 1292 Incorrect inet6 value: '\x01'
+SELECT * FROM t1 WHERE a>0x01;
+a
+Warnings:
+Warning 1292 Incorrect inet6 value: '\x01'
+SELECT * FROM t1 WHERE a='0::0';
+a
+::
+SELECT * FROM t1 WHERE a='0::00';
+a
+::
+SELECT * FROM t1 WHERE a='0::000';
+a
+::
+SELECT * FROM t1 WHERE a='0::0000';
+a
+::
+SELECT * FROM t1 WHERE a=0;
+ERROR HY000: Illegal parameter data types inet6 and int for operation '='
+SELECT * FROM t1 WHERE a=0.0;
+ERROR HY000: Illegal parameter data types inet6 and decimal for operation '='
+SELECT * FROM t1 WHERE a=0e0;
+ERROR HY000: Illegal parameter data types inet6 and double for operation '='
+SELECT * FROM t1 WHERE a=TIME'10:20:30';
+ERROR HY000: Illegal parameter data types inet6 and time for operation '='
+SELECT * FROM t1 WHERE a IN ('::', 10);
+ERROR HY000: Illegal parameter data types inet6 and int for operation 'in'
+DROP TABLE t1;
+#
+# cmp_item_inet6: IN for non-constants
+#
+CREATE TABLE t1 (a INET6, b INET6);
+INSERT INTO t1 VALUES ('::1', '::2');
+SELECT * FROM t1 WHERE '::' IN (a, b);
+a b
+SELECT * FROM t1 WHERE '::1' IN (a, b);
+a b
+::1 ::2
+SELECT * FROM t1 WHERE '::01' IN (a, b);
+a b
+::1 ::2
+SELECT * FROM t1 WHERE '00::01' IN (a, b);
+a b
+::1 ::2
+DROP TABLE t1;
+#
+# cmp_item_inet6: DECODE_ORACLE
+#
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES (NULL),('::01'),('::02');
+SELECT a, DECODE_ORACLE(a, '::01', '01') AS d FROM t1;
+a d
+NULL NULL
+::1 01
+::2 NULL
+SELECT
+a,
+DECODE_ORACLE(a, '::01', '01') AS d0,
+DECODE_ORACLE(a, NULL, '<NULL>', '::01', '01') AS d1,
+DECODE_ORACLE(a, 'garbage', '<NULL>', '::01', '01') AS d2
+FROM t1;
+a d0 d1 d2
+NULL NULL <NULL> <NULL>
+::1 01 01 01
+::2 NULL NULL NULL
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+DROP TABLE t1;
+#
+# CASE abbreviations
+#
+CREATE TABLE t1 (
+c INET6,
+c_char CHAR(32),
+c_varchar VARCHAR(32),
+c_tinytext TINYTEXT,
+c_text TEXT,
+c_mediumtext TEXT,
+c_longtext LONGTEXT
+);
+CREATE TABLE t2 AS SELECT
+COALESCE(c, c_char),
+COALESCE(c, c_varchar),
+COALESCE(c, c_tinytext),
+COALESCE(c, c_text),
+COALESCE(c, c_mediumtext),
+COALESCE(c, c_longtext)
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `COALESCE(c, c_char)` inet6 DEFAULT NULL,
+ `COALESCE(c, c_varchar)` inet6 DEFAULT NULL,
+ `COALESCE(c, c_tinytext)` inet6 DEFAULT NULL,
+ `COALESCE(c, c_text)` inet6 DEFAULT NULL,
+ `COALESCE(c, c_mediumtext)` inet6 DEFAULT NULL,
+ `COALESCE(c, c_longtext)` inet6 DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+CREATE TABLE t2 AS SELECT
+LEAST(c, c_char),
+LEAST(c, c_varchar),
+LEAST(c, c_tinytext),
+LEAST(c, c_text),
+LEAST(c, c_mediumtext),
+LEAST(c, c_longtext)
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `LEAST(c, c_char)` inet6 DEFAULT NULL,
+ `LEAST(c, c_varchar)` inet6 DEFAULT NULL,
+ `LEAST(c, c_tinytext)` inet6 DEFAULT NULL,
+ `LEAST(c, c_text)` inet6 DEFAULT NULL,
+ `LEAST(c, c_mediumtext)` inet6 DEFAULT NULL,
+ `LEAST(c, c_longtext)` inet6 DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES (NULL),('::1'),('::2');
+SELECT COALESCE(a, '::') FROM t1 ORDER BY a;
+COALESCE(a, '::')
+::
+::1
+::2
+SELECT a, LEAST(a,'::0'), LEAST(a,'::f') FROM t1 ORDER BY a;
+a LEAST(a,'::0') LEAST(a,'::f')
+NULL NULL NULL
+::1 :: ::1
+::2 :: ::2
+SELECT a, GREATEST(a,'::0'), GREATEST(a,'::f') FROM t1 ORDER BY a;
+a GREATEST(a,'::0') GREATEST(a,'::f')
+NULL NULL NULL
+::1 ::1 ::f
+::2 ::2 ::f
+CREATE TABLE t2 AS SELECT
+COALESCE(a, '::'),
+LEAST(a,'::'),
+GREATEST(a,'::')
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `COALESCE(a, '::')` inet6 DEFAULT NULL,
+ `LEAST(a,'::')` inet6 DEFAULT NULL,
+ `GREATEST(a,'::')` inet6 DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+SELECT COALESCE(a, 0x00000000000000000000000000000000) FROM t1 ORDER BY a;
+COALESCE(a, 0x00000000000000000000000000000000)
+::
+::1
+::2
+SELECT a,
+LEAST(a, 0x00000000000000000000000000000000),
+LEAST(a, 0x0000000000000000000000000000000f)
+FROM t1 ORDER BY a;
+a LEAST(a, 0x00000000000000000000000000000000) LEAST(a, 0x0000000000000000000000000000000f)
+NULL NULL NULL
+::1 :: ::1
+::2 :: ::2
+SELECT a,
+GREATEST(a, 0x00000000000000000000000000000000),
+GREATEST(a, 0x0000000000000000000000000000000f)
+FROM t1 ORDER BY a;
+a GREATEST(a, 0x00000000000000000000000000000000) GREATEST(a, 0x0000000000000000000000000000000f)
+NULL NULL NULL
+::1 ::1 ::f
+::2 ::2 ::f
+CREATE TABLE t2 AS SELECT
+COALESCE(a, 0x00000000000000000000000000000000),
+LEAST(a,0x00000000000000000000000000000000),
+GREATEST(a,0x00000000000000000000000000000000)
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `COALESCE(a, 0x00000000000000000000000000000000)` inet6 DEFAULT NULL,
+ `LEAST(a,0x00000000000000000000000000000000)` inet6 DEFAULT NULL,
+ `GREATEST(a,0x00000000000000000000000000000000)` inet6 DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+SELECT COALESCE(a, 10) FROM t1;
+ERROR HY000: Illegal parameter data types inet6 and int for operation 'coalesce'
+SELECT LEAST(a, 10) FROM t1;
+ERROR HY000: Illegal parameter data types inet6 and int for operation 'least'
+SELECT GREATEST(a, 10) FROM t1;
+ERROR HY000: Illegal parameter data types inet6 and int for operation 'greatest'
+DROP TABLE t1;
+SELECT COALESCE('garbage', CAST('::1' AS INET6));
+COALESCE('garbage', CAST('::1' AS INET6))
+::1
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage'
+SELECT COALESCE(0x01, CAST('::1' AS INET6));
+COALESCE(0x01, CAST('::1' AS INET6))
+::1
+Warnings:
+Warning 1292 Incorrect inet6 value: '\x01'
+#
+# Uniqueness
+#
+CREATE TABLE t1 (a INET6 NOT NULL PRIMARY KEY);
+INSERT INTO t1 VALUES ('41::1'),('61::1');
+INSERT INTO t1 VALUES ('41::1');
+ERROR 23000: Duplicate entry '41::1' for key 'PRIMARY'
+SELECT * FROM t1;
+a
+41::1
+61::1
+DROP TABLE t1;
+#
+# Indexes
+#
+CREATE TABLE t1 (a INET6, KEY(a(1)));
+ERROR HY000: Incorrect prefix key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique prefix keys
+#
+# Explicit CAST on INSERT
+#
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES (CAST('1::1' AS INET6));
+INSERT INTO t1 VALUES (CAST('1::2' AS INET6));
+INSERT INTO t1 VALUES (CAST('1::3' AS INET6));
+INSERT INTO t1 VALUES (CAST(CONCAT('2','::1') AS INET6));
+INSERT INTO t1 VALUES (CAST(CONCAT('2','::2') AS INET6));
+INSERT INTO t1 VALUES (CAST(CONCAT('2','::3') AS INET6));
+SELECT * FROM t1 ORDER BY a;
+a
+1::1
+1::2
+1::3
+2::1
+2::2
+2::3
+DROP TABLE t1;
+#
+# Explicit CAST and implicit CAST on ALTER
+#
+CREATE TABLE t1 (a VARCHAR(64));
+INSERT INTO t1 VALUES ('garbage'),('::'),('::1'),('ffff::1'),('ffff::2');
+SELECT a, CAST(a AS INET6) FROM t1 ORDER BY a;
+a CAST(a AS INET6)
+:: ::
+::1 ::1
+ffff::1 ffff::1
+ffff::2 ffff::2
+garbage NULL
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage'
+SELECT a, CAST(a AS INET6) FROM t1 ORDER BY CAST(a AS INET6);
+a CAST(a AS INET6)
+garbage NULL
+:: ::
+::1 ::1
+ffff::1 ffff::1
+ffff::2 ffff::2
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+ALTER TABLE t1 MODIFY a INET6;
+ERROR 22007: Incorrect inet6 value: 'garbage' for column `test`.`t1`.`a` at row 1
+SET sql_mode='';
+ALTER TABLE t1 MODIFY a INET6;
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage' for column `test`.`t1`.`a` at row 1
+SET sql_mode=DEFAULT;
+SELECT * FROM t1 ORDER BY a;
+a
+NULL
+::
+::1
+ffff::1
+ffff::2
+DROP TABLE t1;
+CREATE TABLE t1 (a BINARY(16));
+INSERT INTO t1 VALUES (0x00000000000000000000000000000000);
+INSERT INTO t1 VALUES (0x00000000000000000000000000000001);
+INSERT INTO t1 VALUES (0xffff0000000000000000000000000001);
+INSERT INTO t1 VALUES (0xffff0000000000000000000000000002);
+SELECT HEX(a), CAST(a AS INET6) FROM t1 ORDER BY a;
+HEX(a) CAST(a AS INET6)
+00000000000000000000000000000000 ::
+00000000000000000000000000000001 ::1
+FFFF0000000000000000000000000001 ffff::1
+FFFF0000000000000000000000000002 ffff::2
+ALTER TABLE t1 MODIFY a INET6;
+SELECT * FROM t1 ORDER BY a;
+a
+::
+::1
+ffff::1
+ffff::2
+DROP TABLE t1;
+#
+# INSERT..SELECT, same data types
+#
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('::'),('::1'),('::2');
+CREATE TABLE t2 (a INET6);
+INSERT INTO t2 SELECT a FROM t1;
+SELECT * FROM t2;
+a
+::
+::1
+::2
+DROP TABLE t1,t2;
+#
+# Implicit CAST on INSERT..SELECT, text format
+#
+CREATE TABLE t1 (a VARCHAR(64));
+INSERT INTO t1 VALUES ('garbage'),('::'),('::1'),('ffff::1'),('ffff::2');
+CREATE TABLE t2 (a INET6);
+INSERT INTO t2 SELECT a FROM t1;
+ERROR 22007: Incorrect inet6 value: 'garbage' for column `test`.`t2`.`a` at row 1
+SET sql_mode='';
+INSERT INTO t2 SELECT a FROM t1;
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage' for column `test`.`t2`.`a` at row 1
+SELECT * FROM t2 ORDER BY a;
+a
+NULL
+::
+::1
+ffff::1
+ffff::2
+SET sql_mode=DEFAULT;
+DROP TABLE t2;
+CREATE TABLE t2 (a INET6 NOT NULL);
+INSERT INTO t2 SELECT a FROM t1;
+ERROR 22007: Incorrect inet6 value: 'garbage' for column `test`.`t2`.`a` at row 1
+SET sql_mode='';
+INSERT INTO t2 SELECT a FROM t1;
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage' for column `test`.`t2`.`a` at row 1
+SELECT * FROM t2 ORDER BY a;
+a
+::
+::
+::1
+ffff::1
+ffff::2
+SET sql_mode=DEFAULT;
+DROP TABLE t2;
+DROP TABLE t1;
+#
+# Implicit CAST on INSERT..SELECT, binary format
+#
+CREATE TABLE t1 (a BINARY(16));
+INSERT INTO t1 VALUES (0x00000000000000000000000000000000);
+INSERT INTO t1 VALUES (0x00000000000000000000000000000001);
+INSERT INTO t1 VALUES (0xffff0000000000000000000000000001);
+INSERT INTO t1 VALUES (0xffff0000000000000000000000000002);
+CREATE TABLE t2 (a INET6);
+INSERT INTO t2 SELECT a FROM t1;
+SELECT a FROM t2 ORDER BY a;
+a
+::
+::1
+ffff::1
+ffff::2
+DROP TABLE t1,t2;
+#
+# CAST to other data types
+#
+SELECT CAST(CAST('::' AS INET6) AS DOUBLE);
+ERROR HY000: Illegal parameter data type inet6 for operation 'double_typecast'
+SELECT CAST(CAST('::' AS INET6) AS FLOAT);
+ERROR HY000: Illegal parameter data type inet6 for operation 'float_typecast'
+SELECT CAST(CAST('::' AS INET6) AS DECIMAL);
+ERROR HY000: Illegal parameter data type inet6 for operation 'decimal_typecast'
+SELECT CAST(CAST('::' AS INET6) AS SIGNED);
+ERROR HY000: Illegal parameter data type inet6 for operation 'cast_as_signed'
+SELECT CAST(CAST('::' AS INET6) AS UNSIGNED);
+ERROR HY000: Illegal parameter data type inet6 for operation 'cast_as_unsigned'
+SELECT CAST(CAST('::' AS INET6) AS TIME);
+ERROR HY000: Illegal parameter data type inet6 for operation 'cast_as_time'
+SELECT CAST(CAST('::' AS INET6) AS DATE);
+ERROR HY000: Illegal parameter data type inet6 for operation 'cast_as_date'
+SELECT CAST(CAST('::' AS INET6) AS DATETIME);
+ERROR HY000: Illegal parameter data type inet6 for operation 'cast_as_datetime'
+SELECT CAST(CAST('::' AS INET6) AS CHAR);
+CAST(CAST('::' AS INET6) AS CHAR)
+::
+CREATE TABLE t1 AS SELECT CAST(CAST('::' AS INET6) AS CHAR) AS a;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` varchar(39) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('ffff::ffff');
+CREATE TABLE t2 AS SELECT
+CAST(a AS CHAR),
+CAST(a AS CHAR(39)),
+CAST(a AS CHAR(530)),
+CAST(a AS CHAR(65535)),
+CAST(a AS CHAR(66000)),
+CAST(a AS CHAR(16777215)),
+CAST(a AS CHAR(16777216))
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `CAST(a AS CHAR)` varchar(39) DEFAULT NULL,
+ `CAST(a AS CHAR(39))` varchar(39) DEFAULT NULL,
+ `CAST(a AS CHAR(530))` text DEFAULT NULL,
+ `CAST(a AS CHAR(65535))` text DEFAULT NULL,
+ `CAST(a AS CHAR(66000))` mediumtext DEFAULT NULL,
+ `CAST(a AS CHAR(16777215))` mediumtext DEFAULT NULL,
+ `CAST(a AS CHAR(16777216))` longtext DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM t2;
+CAST(a AS CHAR) ffff::ffff
+CAST(a AS CHAR(39)) ffff::ffff
+CAST(a AS CHAR(530)) ffff::ffff
+CAST(a AS CHAR(65535)) ffff::ffff
+CAST(a AS CHAR(66000)) ffff::ffff
+CAST(a AS CHAR(16777215)) ffff::ffff
+CAST(a AS CHAR(16777216)) ffff::ffff
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('ffff::ffff');
+CREATE TABLE t2 AS SELECT
+CAST(a AS BINARY(4)) AS cb4,
+CAST(a AS BINARY) AS cb,
+CAST(a AS BINARY(16)) AS cb16,
+CAST(a AS BINARY(32)) AS cb32,
+CAST(a AS BINARY(530)) AS cb530,
+CAST(a AS BINARY(65535)) AS cb65535,
+CAST(a AS BINARY(66000)) AS cb66000,
+CAST(a AS BINARY(16777215)) AS cb16777215,
+CAST(a AS BINARY(16777216)) AS cb16777216
+FROM t1 LIMIT 0;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `cb4` binary(4) DEFAULT NULL,
+ `cb` binary(16) DEFAULT NULL,
+ `cb16` binary(16) DEFAULT NULL,
+ `cb32` binary(32) DEFAULT NULL,
+ `cb530` varbinary(530) DEFAULT NULL,
+ `cb65535` blob DEFAULT NULL,
+ `cb66000` mediumblob DEFAULT NULL,
+ `cb16777215` mediumblob DEFAULT NULL,
+ `cb16777216` longblob DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+CREATE TABLE t2 AS SELECT
+CAST(a AS BINARY(4)) AS cb4,
+CAST(a AS BINARY) AS cb,
+CAST(a AS BINARY(16)) AS cb16,
+CAST(a AS BINARY(32)) AS cb32,
+CAST(a AS BINARY(530)) AS cb530,
+CAST(a AS BINARY(65535)) AS cb65535
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `cb4` binary(4) DEFAULT NULL,
+ `cb` binary(16) DEFAULT NULL,
+ `cb16` binary(16) DEFAULT NULL,
+ `cb32` binary(32) DEFAULT NULL,
+ `cb530` varbinary(530) DEFAULT NULL,
+ `cb65535` blob DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT
+HEX(cb4),
+HEX(cb),
+HEX(cb16),
+HEX(cb32),
+LENGTH(cb530),
+LENGTH(cb65535)
+FROM t2;
+HEX(cb4) FFFF0000
+HEX(cb) FFFF000000000000000000000000FFFF
+HEX(cb16) FFFF000000000000000000000000FFFF
+HEX(cb32) FFFF000000000000000000000000FFFF00000000000000000000000000000000
+LENGTH(cb530) 530
+LENGTH(cb65535) 65535
+DROP TABLE t2;
+DROP TABLE t1;
+#
+# Implicit conversion to other types in INSERT
+#
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (CAST('::' AS INET6));
+ERROR 22007: Incorrect integer value: '::' for column `test`.`t1`.`a` at row 1
+DROP TABLE t1;
+CREATE TABLE t1 (a DOUBLE);
+INSERT INTO t1 VALUES (CAST('::' AS INET6));
+ERROR 22007: Incorrect double value: '::' for column `test`.`t1`.`a` at row 1
+DROP TABLE t1;
+CREATE TABLE t1 (a DECIMAL(32,0));
+INSERT INTO t1 VALUES (CAST('::' AS INET6));
+ERROR 22007: Incorrect decimal value: '::' for column `test`.`t1`.`a` at row 1
+DROP TABLE t1;
+CREATE TABLE t1 (a VARCHAR(64));
+INSERT INTO t1 VALUES (CAST('::' AS INET6));
+DROP TABLE t1;
+CREATE TABLE t1 (a TEXT);
+INSERT INTO t1 VALUES (CAST('::' AS INET6));
+DROP TABLE t1;
+#
+# Boolean context
+#
+SELECT
+CAST('::' AS INET6) IS TRUE,
+CAST('::' AS INET6) IS FALSE,
+CAST('::1' AS INET6) IS TRUE,
+CAST('::1' AS INET6) IS FALSE;
+CAST('::' AS INET6) IS TRUE CAST('::' AS INET6) IS FALSE CAST('::1' AS INET6) IS TRUE CAST('::1' AS INET6) IS FALSE
+0 1 1 0
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('::'),('::1');
+SELECT a, a IS TRUE, a IS FALSE FROM t1 ORDER BY a;
+a a IS TRUE a IS FALSE
+:: 0 1
+::1 1 0
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('::'),('::1'),('::2');
+SELECT * FROM t1 WHERE a;
+ERROR HY000: Illegal parameter data types inet6 and bigint for operation '<>'
+DROP TABLE t1;
+#
+# GROUP BY
+#
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('::'),('::');
+INSERT INTO t1 VALUES ('::1'),('::01'),('::0001');
+INSERT INTO t1 VALUES ('::2'),('::2'),('::2'),('::2');
+SELECT a, COUNT(*) FROM t1 GROUP BY a;
+a COUNT(*)
+:: 2
+::1 3
+::2 4
+DROP TABLE t1;
+#
+# Aggregate functions
+#
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('::'),('::');
+INSERT INTO t1 VALUES ('::1'),('::01'),('::0001');
+INSERT INTO t1 VALUES ('::2'),('::2'),('::2'),('::2');
+SELECT MIN(a),MAX(a) FROM t1;
+MIN(a) MAX(a)
+:: ::2
+CREATE TABLE t2 AS SELECT MIN(a), MAX(a) FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `MIN(a)` inet6 DEFAULT NULL,
+ `MAX(a)` inet6 DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+SELECT AVG(a) FROM t1;
+ERROR HY000: Illegal parameter data type inet6 for operation 'avg('
+SELECT AVG(DISTINCT a) FROM t1;
+ERROR HY000: Illegal parameter data type inet6 for operation 'avg(distinct '
+SELECT SUM(a) FROM t1;
+ERROR HY000: Illegal parameter data type inet6 for operation 'sum('
+SELECT SUM(DISTINCT a) FROM t1;
+ERROR HY000: Illegal parameter data type inet6 for operation 'sum(distinct '
+SELECT STDDEV(a) FROM t1;
+ERROR HY000: Illegal parameter data type inet6 for operation 'std('
+SELECT GROUP_CONCAT(a ORDER BY a) FROM t1;
+GROUP_CONCAT(a ORDER BY a)
+::,::,::1,::1,::1,::2,::2,::2,::2
+SELECT a, GROUP_CONCAT(a ORDER BY a) FROM t1 GROUP BY a;
+a GROUP_CONCAT(a ORDER BY a)
+:: ::,::
+::1 ::1,::1,::1
+::2 ::2,::2,::2,::2
+DROP TABLE t1;
+#
+# MDEV-21765 Possibly inconsistent behavior of BIT_xx functions with INET6 field
+#
+CREATE TABLE t1 (a INET6);
+SELECT BIT_AND(a) FROM t1;
+ERROR HY000: Illegal parameter data type inet6 for operation 'bit_and('
+SELECT BIT_OR(a) FROM t1;
+ERROR HY000: Illegal parameter data type inet6 for operation 'bit_or('
+SELECT BIT_XOR(a) FROM t1;
+ERROR HY000: Illegal parameter data type inet6 for operation 'bit_xor('
+DROP TABLE t1;
+#
+# Window functions
+#
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('::1'),('::2'),('::3'),('::4');
+SELECT
+a,
+LAG(a) OVER (ORDER BY a),
+LEAD(a) OVER (ORDER BY a)
+FROM t1 ORDER BY a;
+a LAG(a) OVER (ORDER BY a) LEAD(a) OVER (ORDER BY a)
+::1 NULL ::2
+::2 ::1 ::3
+::3 ::2 ::4
+::4 ::3 NULL
+SELECT
+a,
+FIRST_VALUE(a) OVER (ORDER BY a ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING),
+LAST_VALUE(a) OVER (ORDER BY a ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)
+FROM t1 ORDER BY a;
+a FIRST_VALUE(a) OVER (ORDER BY a ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) LAST_VALUE(a) OVER (ORDER BY a ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)
+::1 ::1 ::2
+::2 ::1 ::3
+::3 ::2 ::4
+::4 ::3 ::4
+DROP TABLE t1;
+#
+# Prepared statements
+#
+EXECUTE IMMEDIATE 'CREATE TABLE t1 AS SELECT ? AS a' USING CAST('::' AS INET6);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` inet6 NOT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES (?)' USING '::1';
+EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES (?)' USING CAST('::2' AS INET6);
+EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES (?)' USING 0x00000000000000000000000000000003;
+SELECT a FROM t1 ORDER BY a;
+a
+::
+::1
+::2
+::3
+EXECUTE IMMEDIATE 'SELECT * FROM t1 WHERE a=?' USING '::1';
+a
+::1
+EXECUTE IMMEDIATE 'SELECT * FROM t1 WHERE a=?' USING CAST('::2' AS INET6);
+a
+::2
+EXECUTE IMMEDIATE 'SELECT * FROM t1 WHERE a=?' USING 0x00000000000000000000000000000003;
+a
+::3
+DROP TABLE t1;
+#
+# Character set and collation aggregation
+#
+CREATE TABLE t1 (a INET6);
+CREATE TABLE t2 AS SELECT
+CONCAT(a) AS c1,
+CONCAT(CAST('::' AS INET6)) AS c2
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c1` varchar(39) DEFAULT NULL,
+ `c2` varchar(39) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+CREATE TABLE t2 AS SELECT
+CONCAT(_utf8'1', a) AS c1,
+CONCAT(_utf8'1', CAST('::1' AS INET6)) AS c2,
+CONCAT(_utf8'1', COALESCE(a)) AS c3
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c1` varchar(40) CHARACTER SET utf8 DEFAULT NULL,
+ `c2` varchar(40) CHARACTER SET utf8 DEFAULT NULL,
+ `c3` varchar(40) CHARACTER SET utf8 DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+CREATE TABLE t2 AS SELECT
+CONCAT(_latin1'1', a) AS c1,
+CONCAT(_latin1'1', CAST('::1' AS INET6)) AS c2,
+CONCAT(_latin1'1', COALESCE(a)) AS c3
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c1` varchar(40) DEFAULT NULL,
+ `c2` varchar(40) DEFAULT NULL,
+ `c3` varchar(40) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+#
+# UNION
+#
+CREATE TABLE t1 AS SELECT CAST('::' AS INET6) AS c UNION SELECT CAST('::1' AS INET6);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c` inet6 NOT NULL DEFAULT '::'
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1 AS SELECT CAST('::' AS INET6) AS c UNION SELECT '::1';
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c` inet6 NOT NULL DEFAULT '::'
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1 AS SELECT '::' AS c UNION SELECT CAST('::1' AS INET6);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c` inet6 NOT NULL DEFAULT '::'
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1 AS SELECT CAST('::' AS INET6) AS c UNION SELECT 0x00000000000000000000000000000001;
+SELECT * FROM t1;
+c
+::
+::1
+DROP TABLE t1;
+CREATE TABLE t1 AS SELECT CAST('::' AS INET6) AS c UNION SELECT 1;
+ERROR HY000: Illegal parameter data types inet6 and int for operation 'UNION'
+#
+# Unary operators
+#
+SELECT -CAST('::' AS INET6);
+ERROR HY000: Illegal parameter data type inet6 for operation '-'
+SELECT ABS(CAST('::' AS INET6));
+ERROR HY000: Illegal parameter data type inet6 for operation 'abs'
+SELECT ROUND(CAST('::' AS INET6));
+ERROR HY000: Illegal parameter data type inet6 for operation 'round'
+SELECT CEILING(CAST('::' AS INET6));
+ERROR HY000: Illegal parameter data type inet6 for operation 'ceiling'
+SELECT FLOOR(CAST('::' AS INET6));
+ERROR HY000: Illegal parameter data type inet6 for operation 'floor'
+#
+# Arithmetic operators
+#
+SELECT CAST('::' AS INET6) + 1;
+ERROR HY000: Illegal parameter data types inet6 and int for operation '+'
+SELECT CAST('::' AS INET6) - 1;
+ERROR HY000: Illegal parameter data types inet6 and int for operation '-'
+SELECT CAST('::' AS INET6) * 1;
+ERROR HY000: Illegal parameter data types inet6 and int for operation '*'
+SELECT CAST('::' AS INET6) / 1;
+ERROR HY000: Illegal parameter data types inet6 and int for operation '/'
+SELECT CAST('::' AS INET6) MOD 1;
+ERROR HY000: Illegal parameter data types inet6 and int for operation 'MOD'
+#
+# Misc
+#
+SELECT RAND(CAST('::' AS INET6));
+ERROR HY000: Illegal parameter data type inet6 for operation 'rand'
+SELECT FROM_UNIXTIME(CAST('::' AS INET6));
+ERROR HY000: Illegal parameter data type inet6 for operation 'from_unixtime'
+SELECT HOUR(CAST('::' AS INET6));
+ERROR HY000: Illegal parameter data type inet6 for operation 'hour'
+SELECT YEAR(CAST('::' AS INET6));
+ERROR HY000: Illegal parameter data type inet6 for operation 'year'
+SELECT RELEASE_LOCK(CAST('::' AS INET6));
+ERROR HY000: Illegal parameter data type inet6 for operation 'release_lock'
+SELECT JSON_LENGTH(CAST('::' AS INET6));
+JSON_LENGTH(CAST('::' AS INET6))
+NULL
+Warnings:
+Warning 4038 Syntax error in JSON text in argument 1 to function 'json_length' at position 1
+#
+# Virtual columns
+#
+CREATE TABLE t1 (
+a INT,
+b INET6 GENERATED ALWAYS AS (CAST(CONCAT(RAND(),a) AS INET6)), INDEX(b)
+);
+ERROR HY000: Function or expression 'rand()' cannot be used in the GENERATED ALWAYS AS clause of `b`
+CREATE TABLE t1 (
+a INT,
+b INET6 GENERATED ALWAYS AS (CAST(CONCAT('::',HEX(a)) AS INET6)), INDEX(b)
+);
+INSERT INTO t1 (a) VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15);
+SELECT * FROM t1;
+a b
+0 ::
+1 ::1
+2 ::2
+3 ::3
+4 ::4
+5 ::5
+6 ::6
+7 ::7
+8 ::8
+9 ::9
+10 ::a
+11 ::b
+12 ::c
+13 ::d
+14 ::e
+15 ::f
+DROP TABLE t1;
+#
+# VIEW
+#
+CREATE TABLE t1 (a INT DEFAULT 0);
+INSERT INTO t1 (a) VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15);
+SELECT * FROM t1 ORDER BY a;
+a
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+CREATE VIEW v1 AS SELECT (CAST(CONCAT('::',HEX(a)) AS INET6)) AS c FROM t1;
+SELECT * FROM v1 ORDER BY c;
+c
+::
+::1
+::2
+::3
+::4
+::5
+::6
+::7
+::8
+::9
+::a
+::b
+::c
+::d
+::e
+::f
+DROP VIEW v1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6 DEFAULT '::');
+CREATE VIEW v1 AS SELECT * FROM t1;
+SHOW CREATE VIEW v1;
+View Create View character_set_client collation_connection
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a` from `t1` latin1 latin1_swedish_ci
+DESCRIBE v1;
+Field Type Null Key Default Extra
+a inet6 YES ::
+INSERT INTO v1 VALUES ('::'),('::1'),('::2');
+SELECT * FROM t1;
+a
+::
+::1
+::2
+DROP VIEW v1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6 DEFAULT CAST('::' AS INET6));
+CREATE VIEW v1 AS SELECT * FROM t1;
+SHOW CREATE VIEW v1;
+View Create View character_set_client collation_connection
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a` from `t1` latin1 latin1_swedish_ci
+DESCRIBE v1;
+Field Type Null Key Default Extra
+a inet6 YES cast('::' as inet6)
+INSERT INTO v1 VALUES ('::'),('::1'),('::2');
+SELECT * FROM t1;
+a
+::
+::1
+::2
+DROP VIEW v1;
+DROP TABLE t1;
+#
+# Subqueries
+#
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('::'),('::1'),('::2');
+SELECT * FROM t1 WHERE a=(SELECT MIN(a) FROM t1) ORDER BY a;
+a
+::
+SELECT * FROM t1 WHERE a=(SELECT MAX(a) FROM t1) ORDER BY a;
+a
+::2
+SELECT * FROM t1 WHERE a IN (SELECT a FROM t1 WHERE a>'::') ORDER BY a;
+a
+::1
+::2
+DROP TABLE t1;
+#
+# Stored routines
+#
+CREATE PROCEDURE p1(a INET6)
+BEGIN
+DECLARE b INET6 DEFAULT CONCAT('1', a);
+SELECT a, b;
+END;
+$$
+CALL p1('::1');
+a b
+::1 1::1
+CALL p1(CAST('::2' AS INET6));
+a b
+::2 1::2
+DROP PROCEDURE p1;
+CREATE FUNCTION f1(a INET6) RETURNS INET6
+BEGIN
+RETURN CONCAT('1',a);
+END;
+$$
+SELECT f1('::1');
+f1('::1')
+1::1
+SELECT f1(CAST('::1' AS INET6));
+f1(CAST('::1' AS INET6))
+1::1
+DROP FUNCTION f1;
+#
+# Anchored data types in SP variables
+#
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('::1');
+CREATE PROCEDURE p1()
+BEGIN
+DECLARE va TYPE OF t1.a;
+SELECT MAX(a) INTO va FROM t1;
+SELECT va;
+END;
+$$
+CALL p1;
+va
+::1
+DROP PROCEDURE p1;
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6, b INET6);
+INSERT INTO t1 VALUES ('::a', '::b');
+CREATE PROCEDURE p1()
+BEGIN
+DECLARE va ROW TYPE OF t1;
+SELECT MAX(a), MAX(b) INTO va FROM t1;
+SELECT va.a, va.b;
+END;
+$$
+CALL p1;
+va.a va.b
+::a ::b
+DROP PROCEDURE p1;
+DROP TABLE t1;
+#
+# Optimizer: make_const_item_for_comparison
+#
+CREATE TABLE t1 (id INT, a INET6);
+INSERT INTO t1 VALUES (1,'::1'),(2,'::2');
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=COALESCE(CAST('::1' AS INET6)) AND id>0;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t1`.`id` AS `id`,`test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = INET6'::1' and `test`.`t1`.`id` > 0
+DROP TABLE t1;
+#
+# Optimizer: equal field propagation
+#
+CREATE TABLE t1 (id INT, a INET6);
+INSERT INTO t1 VALUES (1,'::1'),(2,'::2');
+EXPLAIN EXTENDED SELECT * FROM t1
+WHERE a=COALESCE(CAST('::1' AS INET6))
+AND LENGTH(CONCAT(a,RAND()))>1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t1`.`id` AS `id`,`test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = INET6'::1' and octet_length(concat(INET6'::1',rand())) > 1
+EXPLAIN EXTENDED SELECT * FROM t1
+WHERE a=COALESCE(CAST('::1' AS INET6))
+AND LENGTH(a)>1;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t1`.`id` AS `id`,`test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = INET6'::1'
+DROP TABLE t1;
+#
+# Optimizer: equal expression propagation
+#
+CREATE TABLE t1 (id INT, a INET6);
+INSERT INTO t1 VALUES (1,'::1'),(2,'::2');
+EXPLAIN EXTENDED SELECT * FROM t1
+WHERE COALESCE(a)='::1' AND COALESCE(a)=CONCAT(a);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t1`.`id` AS `id`,`test`.`t1`.`a` AS `a` from `test`.`t1` where coalesce(`test`.`t1`.`a`) = '::1' and concat(`test`.`t1`.`a`) = '::1'
+DROP TABLE t1;
+#
+# Subquery materialization
+#
+CREATE TABLE t1 (a INET6, b VARCHAR(32), KEY (a), KEY(b)) ;
+INSERT INTO t1 VALUES ('::a','::a'),('::a','::b');
+SET @@optimizer_switch='semijoin=off,materialization=on,in_to_exists=off,subquery_cache=off';
+EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT a AS a_inner FROM t1 GROUP BY a_inner);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
+2 MATERIALIZED t1 index NULL a 17 NULL 2 Using index
+EXPLAIN SELECT * FROM t1 WHERE b IN (SELECT a AS a_inner FROM t1 GROUP BY a_inner);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where
+2 DEPENDENT SUBQUERY t1 index_subquery a a 17 func 2 Using index; Using where
+SET @@optimizer_switch=DEFAULT;
+DROP TABLE t1;
+#
+# IS_IPV4_MAPPED(), IS_IPV4_COMPAT() now understand text notation
+#
+CREATE TABLE t1 (id SERIAL, a VARCHAR(32));
+INSERT INTO t1 (a) VALUES ('::192.168.0.1'),('::192.168.10.111'),('::ffff:10.10.0.1'),('::ffff:192.168.0.1');
+# This is a text notation
+SELECT id, length(a), a, IS_IPV4_MAPPED(a) FROM t1 ORDER BY id;
+id length(a) a IS_IPV4_MAPPED(a)
+1 13 ::192.168.0.1 0
+2 16 ::192.168.10.111 0
+3 16 ::ffff:10.10.0.1 1
+4 18 ::ffff:192.168.0.1 1
+SELECT id, length(a), a, IS_IPV4_COMPAT(a) FROM t1 ORDER BY id;
+id length(a) a IS_IPV4_COMPAT(a)
+1 13 ::192.168.0.1 1
+2 16 ::192.168.10.111 1
+3 16 ::ffff:10.10.0.1 0
+4 18 ::ffff:192.168.0.1 0
+# This is not a text notation: it is a binary input only looking like text notation
+SELECT id, length(a), a, IS_IPV4_MAPPED(BINARY a) FROM t1 ORDER BY id;
+id length(a) a IS_IPV4_MAPPED(BINARY a)
+1 13 ::192.168.0.1 0
+2 16 ::192.168.10.111 0
+3 16 ::ffff:10.10.0.1 0
+4 18 ::ffff:192.168.0.1 0
+Warnings:
+Warning 1292 Incorrect inet6 value: '::192.168.0.1'
+Warning 1292 Incorrect inet6 value: '::ffff:192.168.0.1'
+SELECT id, length(a), a, IS_IPV4_COMPAT(BINARY a) FROM t1 ORDER BY id;
+id length(a) a IS_IPV4_COMPAT(BINARY a)
+1 13 ::192.168.0.1 0
+2 16 ::192.168.10.111 0
+3 16 ::ffff:10.10.0.1 0
+4 18 ::ffff:192.168.0.1 0
+Warnings:
+Warning 1292 Incorrect inet6 value: '::192.168.0.1'
+Warning 1292 Incorrect inet6 value: '::ffff:192.168.0.1'
+DROP TABLE t1;
+#
+# ALTER from INET6 to INET6
+#
+CREATE TABLE t1 (a INET6, b INT);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329', 1);
+ALTER TABLE t1 MODIFY b DECIMAL(10,2);
+SELECT * FROM t1;
+a b
+2001:db8::ff00:42:8329 1.00
+DROP TABLE t1;
+#
+# ALTER to character string data types
+#
+CREATE OR REPLACE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+SELECT CAST(a AS CHAR(39)) FROM t1;
+CAST(a AS CHAR(39))
+2001:db8::ff00:42:8329
+ALTER TABLE t1 MODIFY a CHAR(39);
+SELECT * FROM t1;
+a
+2001:db8::ff00:42:8329
+DROP TABLE t1;
+CREATE OR REPLACE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+ALTER TABLE t1 MODIFY a VARCHAR(39);
+SELECT * FROM t1;
+a
+2001:db8::ff00:42:8329
+DROP TABLE t1;
+CREATE OR REPLACE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+ALTER TABLE t1 MODIFY a TINYTEXT;
+SELECT * FROM t1;
+a
+2001:db8::ff00:42:8329
+DROP TABLE t1;
+CREATE OR REPLACE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+ALTER TABLE t1 MODIFY a TEXT;
+SELECT * FROM t1;
+a
+2001:db8::ff00:42:8329
+DROP TABLE t1;
+CREATE OR REPLACE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+ALTER TABLE t1 MODIFY a MEDIUMTEXT;
+SELECT * FROM t1;
+a
+2001:db8::ff00:42:8329
+DROP TABLE t1;
+CREATE OR REPLACE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+ALTER TABLE t1 MODIFY a LONGTEXT;
+SELECT * FROM t1;
+a
+2001:db8::ff00:42:8329
+DROP TABLE t1;
+#
+# ALTER from character string data types
+#
+CREATE OR REPLACE TABLE t1 (a CHAR(64));
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+SELECT CAST(a AS INET6) FROM t1;
+CAST(a AS INET6)
+2001:db8::ff00:42:8329
+ALTER TABLE t1 MODIFY a INET6;
+SELECT * FROM t1;
+a
+2001:db8::ff00:42:8329
+DROP TABLE t1;
+CREATE OR REPLACE TABLE t1 (a VARCHAR(64));
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+SELECT CAST(a AS INET6) FROM t1;
+CAST(a AS INET6)
+2001:db8::ff00:42:8329
+ALTER TABLE t1 MODIFY a INET6;
+SELECT * FROM t1;
+a
+2001:db8::ff00:42:8329
+DROP TABLE t1;
+CREATE OR REPLACE TABLE t1 (a TINYTEXT);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+SELECT CAST(a AS INET6) FROM t1;
+CAST(a AS INET6)
+2001:db8::ff00:42:8329
+ALTER TABLE t1 MODIFY a INET6;
+SELECT * FROM t1;
+a
+2001:db8::ff00:42:8329
+DROP TABLE t1;
+CREATE OR REPLACE TABLE t1 (a TEXT);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+SELECT CAST(a AS INET6) FROM t1;
+CAST(a AS INET6)
+2001:db8::ff00:42:8329
+ALTER TABLE t1 MODIFY a INET6;
+SELECT * FROM t1;
+a
+2001:db8::ff00:42:8329
+DROP TABLE t1;
+CREATE OR REPLACE TABLE t1 (a MEDIUMTEXT);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+SELECT CAST(a AS INET6) FROM t1;
+CAST(a AS INET6)
+2001:db8::ff00:42:8329
+ALTER TABLE t1 MODIFY a INET6;
+SELECT * FROM t1;
+a
+2001:db8::ff00:42:8329
+DROP TABLE t1;
+CREATE OR REPLACE TABLE t1 (a LONGTEXT);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+SELECT CAST(a AS INET6) FROM t1;
+CAST(a AS INET6)
+2001:db8::ff00:42:8329
+ALTER TABLE t1 MODIFY a INET6;
+SELECT * FROM t1;
+a
+2001:db8::ff00:42:8329
+DROP TABLE t1;
+#
+# ALTER to binary string data types
+#
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+ALTER TABLE t1 MODIFY a BINARY(16);
+SELECT HEX(a) FROM t1;
+HEX(a)
+20010DB8000000000000FF0000428329
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+ALTER TABLE t1 MODIFY a BINARY(17);
+SELECT HEX(a) FROM t1;
+HEX(a)
+20010DB8000000000000FF000042832900
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+ALTER TABLE t1 MODIFY a BINARY(15);
+ERROR 22001: Data too long for column 'a' at row 1
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+ALTER TABLE t1 MODIFY a TINYBLOB;
+SELECT HEX(a) FROM t1;
+HEX(a)
+20010DB8000000000000FF0000428329
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+ALTER TABLE t1 MODIFY a BLOB;
+SELECT HEX(a) FROM t1;
+HEX(a)
+20010DB8000000000000FF0000428329
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+ALTER TABLE t1 MODIFY a MEDIUMBLOB;
+SELECT HEX(a) FROM t1;
+HEX(a)
+20010DB8000000000000FF0000428329
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+ALTER TABLE t1 MODIFY a LONGBLOB;
+SELECT HEX(a) FROM t1;
+HEX(a)
+20010DB8000000000000FF0000428329
+DROP TABLE t1;
+#
+# ALTER from binary string data types
+#
+CREATE TABLE t1 (a BINARY(16));
+INSERT INTO t1 VALUES (X'20010DB8000000000000FF0000428329');
+ALTER TABLE t1 MODIFY a INET6;
+SELECT a FROM t1;
+a
+2001:db8::ff00:42:8329
+DROP TABLE t1;
+CREATE TABLE t1 (a BINARY(17));
+INSERT INTO t1 VALUES (X'20010DB8000000000000FF000042832900');
+ALTER TABLE t1 MODIFY a INET6;
+ERROR 22007: Incorrect inet6 value: ' \x01\x0D\xB8\x00\x00\x00\x00\x00\x00\xFF\x00\x00B\x83)\x00' for column `test`.`t1`.`a` at row 1
+DROP TABLE t1;
+CREATE TABLE t1 (a BINARY(15));
+INSERT INTO t1 VALUES (X'20010DB8000000000000FF00004283');
+ALTER TABLE t1 MODIFY a INET6;
+ERROR 22007: Incorrect inet6 value: ' \x01\x0D\xB8\x00\x00\x00\x00\x00\x00\xFF\x00\x00B\x83' for column `test`.`t1`.`a` at row 1
+DROP TABLE t1;
+CREATE TABLE t1 (a TINYBLOB);
+INSERT INTO t1 VALUES (X'20010DB8000000000000FF0000428329');
+ALTER TABLE t1 MODIFY a INET6;
+SELECT a FROM t1;
+a
+2001:db8::ff00:42:8329
+DROP TABLE t1;
+CREATE TABLE t1 (a BLOB);
+INSERT INTO t1 VALUES (X'20010DB8000000000000FF0000428329');
+ALTER TABLE t1 MODIFY a INET6;
+SELECT a FROM t1;
+a
+2001:db8::ff00:42:8329
+DROP TABLE t1;
+CREATE TABLE t1 (a MEDIUMBLOB);
+INSERT INTO t1 VALUES (X'20010DB8000000000000FF0000428329');
+ALTER TABLE t1 MODIFY a INET6;
+SELECT a FROM t1;
+a
+2001:db8::ff00:42:8329
+DROP TABLE t1;
+CREATE TABLE t1 (a BLOB);
+INSERT INTO t1 VALUES (X'20010DB8000000000000FF0000428329');
+ALTER TABLE t1 MODIFY a INET6;
+SELECT a FROM t1;
+a
+2001:db8::ff00:42:8329
+DROP TABLE t1;
+#
+# SET from INET6 to INET6
+#
+CREATE TABLE t1 (a INET6, b INET6);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+b
+ffff::ffff
+DROP TABLE t1;
+#
+# SET from INET6 to numeric
+#
+CREATE TABLE t1 (a INET6, b INT);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+ERROR 22007: Incorrect integer value: 'ffff::ffff' for column `test`.`t1`.`b` at row 1
+SELECT b FROM t1;
+b
+NULL
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6, b DOUBLE);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+ERROR 22007: Incorrect double value: 'ffff::ffff' for column `test`.`t1`.`b` at row 1
+SELECT b FROM t1;
+b
+NULL
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6, b DECIMAL(32,0));
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+ERROR 22007: Incorrect decimal value: 'ffff::ffff' for column `test`.`t1`.`b` at row 1
+SELECT b FROM t1;
+b
+NULL
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6, b YEAR);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+ERROR 22007: Incorrect integer value: 'ffff::ffff' for column `test`.`t1`.`b` at row 1
+SELECT b FROM t1;
+b
+NULL
+DROP TABLE t1;
+#
+# SET from numeric to INET6
+#
+CREATE TABLE t1 (a INT, b INET6);
+INSERT INTO t1 VALUES (1, NULL);
+UPDATE t1 SET b=a;
+ERROR 22007: Incorrect inet6 value: '1' for column `test`.`t1`.`b` at row 1
+SELECT b FROM t1;
+b
+NULL
+DROP TABLE t1;
+CREATE TABLE t1 (a DOUBLE, b INET6);
+INSERT INTO t1 VALUES (1, NULL);
+UPDATE t1 SET b=a;
+ERROR 22007: Incorrect inet6 value: '1' for column `test`.`t1`.`b` at row 1
+SELECT b FROM t1;
+b
+NULL
+DROP TABLE t1;
+CREATE TABLE t1 (a DECIMAL(32,0), b INET6);
+INSERT INTO t1 VALUES (1, NULL);
+UPDATE t1 SET b=a;
+ERROR 22007: Incorrect inet6 value: '1' for column `test`.`t1`.`b` at row 1
+SELECT b FROM t1;
+b
+NULL
+DROP TABLE t1;
+CREATE TABLE t1 (a YEAR, b INET6);
+INSERT INTO t1 VALUES (1, NULL);
+UPDATE t1 SET b=a;
+ERROR 22007: Incorrect inet6 value: '2001' for column `test`.`t1`.`b` at row 1
+SELECT b FROM t1;
+b
+NULL
+DROP TABLE t1;
+#
+# SET from INET6 to temporal
+#
+CREATE TABLE t1 (a INET6, b TIME);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+ERROR 22007: Incorrect time value: 'ffff::ffff' for column `test`.`t1`.`b` at row 1
+SELECT b FROM t1;
+b
+NULL
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6, b DATE);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+ERROR 22007: Incorrect date value: 'ffff::ffff' for column `test`.`t1`.`b` at row 1
+SELECT b FROM t1;
+b
+NULL
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6, b DATETIME);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+ERROR 22007: Incorrect datetime value: 'ffff::ffff' for column `test`.`t1`.`b` at row 1
+SELECT b FROM t1;
+b
+NULL
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6, b TIMESTAMP NULL DEFAULT NULL);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+ERROR 22007: Incorrect datetime value: 'ffff::ffff' for column `test`.`t1`.`b` at row 1
+SELECT b FROM t1;
+b
+NULL
+DROP TABLE t1;
+#
+# SET from temporal to INET6
+#
+CREATE TABLE t1 (a TIME, b INET6);
+INSERT INTO t1 VALUES ('00:00:00', NULL);
+UPDATE t1 SET b=a;
+ERROR 22007: Incorrect inet6 value: '00:00:00' for column `test`.`t1`.`b` at row 1
+SELECT b FROM t1;
+b
+NULL
+DROP TABLE t1;
+CREATE TABLE t1 (a DATE, b INET6);
+INSERT INTO t1 VALUES ('2001-01:01', NULL);
+UPDATE t1 SET b=a;
+ERROR 22007: Incorrect inet6 value: '2001-01-01' for column `test`.`t1`.`b` at row 1
+SELECT b FROM t1;
+b
+NULL
+DROP TABLE t1;
+CREATE TABLE t1 (a DATETIME, b INET6);
+INSERT INTO t1 VALUES ('2001-01-01 10:20:30', NULL);
+UPDATE t1 SET b=a;
+ERROR 22007: Incorrect inet6 value: '2001-01-01 10:20:30' for column `test`.`t1`.`b` at row 1
+SELECT b FROM t1;
+b
+NULL
+DROP TABLE t1;
+CREATE TABLE t1 (a TIMESTAMP, b INET6);
+INSERT INTO t1 VALUES ('2001-01-01 10:20:30', NULL);
+UPDATE t1 SET b=a;
+ERROR 22007: Incorrect inet6 value: '2001-01-01 10:20:30' for column `test`.`t1`.`b` at row 1
+SELECT b FROM t1;
+b
+NULL
+DROP TABLE t1;
+#
+# SET from INET6 to character string
+#
+CREATE TABLE t1 (a INET6, b CHAR(39));
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+b
+ffff::ffff
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6, b VARCHAR(39));
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+b
+ffff::ffff
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6, b TEXT);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+b
+ffff::ffff
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6, b ENUM('ffff::ffff'));
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+b
+ffff::ffff
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6, b SET('ffff::ffff'));
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+b
+ffff::ffff
+DROP TABLE t1;
+#
+# SET from character string to INET6
+#
+CREATE TABLE t1 (a CHAR(39), b INET6);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+b
+ffff::ffff
+DROP TABLE t1;
+CREATE TABLE t1 (a VARCHAR(39), b INET6);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+b
+ffff::ffff
+DROP TABLE t1;
+CREATE TABLE t1 (a TEXT, b INET6);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+b
+ffff::ffff
+DROP TABLE t1;
+CREATE TABLE t1 (a ENUM('ffff::ffff'), b INET6);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+b
+ffff::ffff
+DROP TABLE t1;
+CREATE TABLE t1 (a SET('ffff::ffff'), b INET6);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+b
+ffff::ffff
+DROP TABLE t1;
+#
+# SET from INET6 to binary
+#
+CREATE TABLE t1 (a INET6, b BINARY(16));
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT HEX(b) FROM t1;
+HEX(b)
+FFFF000000000000000000000000FFFF
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6, b VARBINARY(39));
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT HEX(b) FROM t1;
+HEX(b)
+FFFF000000000000000000000000FFFF
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6, b BLOB);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT HEX(b) FROM t1;
+HEX(b)
+FFFF000000000000000000000000FFFF
+DROP TABLE t1;
+#
+# SET from binary to INET6
+#
+CREATE TABLE t1 (a BINARY(16), b INET6);
+INSERT INTO t1 VALUES (CONCAT(0xFFFF,REPEAT(0x0000,6),0xFFFF), NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+b
+ffff::ffff
+DROP TABLE t1;
+CREATE TABLE t1 (a VARBINARY(16), b INET6);
+INSERT INTO t1 VALUES (CONCAT(0xFFFF,REPEAT(0x0000,6),0xFFFF), NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+b
+ffff::ffff
+DROP TABLE t1;
+CREATE TABLE t1 (a BLOB, b INET6);
+INSERT INTO t1 VALUES (CONCAT(0xFFFF,REPEAT(0x0000,6),0xFFFF), NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+b
+ffff::ffff
+DROP TABLE t1;
+#
+# Limit clause parameter
+# TODO: this should fail.
+# The test for a valid data type should be moved
+# from parse time to fix_fields() time, and performed
+# for both Item_splocal and Item_param.
+#
+EXECUTE IMMEDIATE 'SELECT 1 FROM DUAL LIMIT ?' USING CAST('::' AS INET6);
+1
+#
+# MDEV-20785 Converting INET6 to CHAR(39) produces garbage without a warning
+#
+CREATE OR REPLACE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+SELECT CAST(a AS CHAR(39)) FROM t1;
+CAST(a AS CHAR(39))
+2001:db8::ff00:42:8329
+ALTER TABLE t1 MODIFY a CHAR(39);
+SELECT * FROM t1;
+a
+2001:db8::ff00:42:8329
+DROP TABLE t1;
+#
+# MDEV-20783 INET6 cannot be converted to BINARY(16) (requires clarification in documentation)
+#
+CREATE OR REPLACE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+ALTER TABLE t1 MODIFY a BINARY(16);
+SELECT HEX(a) FROM t1;
+HEX(a)
+20010DB8000000000000FF0000428329
+DROP TABLE t1;
+#
+# MDEV-20795 CAST(inet6 AS BINARY) returns wrong result
+#
+CREATE OR REPLACE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+SELECT HEX(CAST(a AS BINARY)) FROM t1;
+HEX(CAST(a AS BINARY))
+20010DB8000000000000FF0000428329
+SELECT HEX(CAST(a AS BINARY(16))) FROM t1;
+HEX(CAST(a AS BINARY(16)))
+20010DB8000000000000FF0000428329
+DROP TABLE t1;
+#
+# MDEV-20808 CAST from INET6 to FLOAT does not produce an error
+#
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('::');
+SELECT CAST(a AS FLOAT) FROM t1;
+ERROR HY000: Illegal parameter data type inet6 for operation 'float_typecast'
+DROP TABLE t1;
+#
+# MDEV-20798 Conversion from INET6 to other types performed without errors or warnings
+#
+CREATE TABLE t1 (a INET6, b INT);
+INSERT INTO t1 (a) VALUES ('::');
+UPDATE t1 SET b=a;
+ERROR 22007: Incorrect integer value: '::' for column `test`.`t1`.`b` at row 1
+SELECT * FROM t1;
+a b
+:: NULL
+DROP TABLE t1;
+SET timestamp=UNIX_TIMESTAMP('2001-01-01 10:20:30');
+CREATE TABLE t1 (a INET6, b TIMESTAMP);
+INSERT INTO t1 (a) VALUES ('::');
+UPDATE t1 SET b=a;
+ERROR 22007: Incorrect datetime value: '::' for column `test`.`t1`.`b` at row 1
+SELECT * FROM t1;
+a b
+:: 2001-01-01 10:20:30
+DROP TABLE t1;
+SET timestamp=DEFAULT;
+CREATE OR REPLACE TABLE t1 (a INET6);
+INSERT INTO t1 (a) VALUES ('::');
+ALTER TABLE t1 MODIFY a DATE;
+ERROR 22007: Incorrect date value: '::' for column `test`.`t1`.`a` at row 1
+DROP TABLE t1;
+#
+# MDEV-20818 ER_CRASHED_ON_USAGE or Assertion `length <= column->length' failed in write_block_record on temporary table
+#
+CREATE TABLE t1 (a INET6);
+SELECT
+CAST(a AS BINARY(0)),
+CAST(a AS BINARY(1)),
+CAST(a AS BINARY(16)),
+CAST(a AS BINARY(255)),
+CAST(a AS BINARY(256)),
+CAST(a AS BINARY(512)),
+CAST(a AS BINARY(513)),
+CAST(a AS BINARY(65532)),
+CAST(a AS BINARY(65533)),
+CAST(a AS BINARY(65534)),
+CAST(a AS BINARY(65535)),
+CAST(a AS BINARY(65536)),
+CAST(a AS BINARY(16777215)),
+CAST(a AS BINARY(16777216))
+FROM t1;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def CAST(a AS BINARY(0)) 254 0 0 Y 128 0 63
+def CAST(a AS BINARY(1)) 254 1 0 Y 128 0 63
+def CAST(a AS BINARY(16)) 254 16 0 Y 128 0 63
+def CAST(a AS BINARY(255)) 254 255 0 Y 128 0 63
+def CAST(a AS BINARY(256)) 253 256 0 Y 128 0 63
+def CAST(a AS BINARY(512)) 253 512 0 Y 128 0 63
+def CAST(a AS BINARY(513)) 253 513 0 Y 128 0 63
+def CAST(a AS BINARY(65532)) 253 65532 0 Y 128 0 63
+def CAST(a AS BINARY(65533)) 252 65533 0 Y 128 0 63
+def CAST(a AS BINARY(65534)) 252 65534 0 Y 128 0 63
+def CAST(a AS BINARY(65535)) 252 65535 0 Y 128 0 63
+def CAST(a AS BINARY(65536)) 250 65536 0 Y 128 0 63
+def CAST(a AS BINARY(16777215)) 250 16777215 0 Y 128 0 63
+def CAST(a AS BINARY(16777216)) 251 16777216 0 Y 128 0 63
+CAST(a AS BINARY(0)) CAST(a AS BINARY(1)) CAST(a AS BINARY(16)) CAST(a AS BINARY(255)) CAST(a AS BINARY(256)) CAST(a AS BINARY(512)) CAST(a AS BINARY(513)) CAST(a AS BINARY(65532)) CAST(a AS BINARY(65533)) CAST(a AS BINARY(65534)) CAST(a AS BINARY(65535)) CAST(a AS BINARY(65536)) CAST(a AS BINARY(16777215)) CAST(a AS BINARY(16777216))
+DROP TABLE t1;
+#
+# MDEV-20826 Wrong result of MIN(inet6) with GROUP BY
+#
+CREATE TABLE t1 (id INT, a INET6) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (1, 'fff::'),(1, '8888::');
+SELECT MIN(a), MAX(a) FROM t1 GROUP BY id;
+MIN(a) MAX(a)
+fff:: 8888::
+DROP TABLE t1;
+#
+# MDEV-20809 EXTRACT from INET6 value does not produce any warnings
+#
+CREATE TABLE t1 (a INET6);
+SELECT EXTRACT(DAY FROM a) FROM t1;
+ERROR HY000: Illegal parameter data type inet6 for operation 'extract(day)'
+DROP TABLE t1;
+SELECT EXTRACT(DAY FROM CAST('::' AS INET6));
+ERROR HY000: Illegal parameter data type inet6 for operation 'extract(day)'
+#
+# MDEV-22764 Crash with a stored aggregate function returning INET6
+#
+CREATE OR REPLACE AGGREGATE FUNCTION aggregate_min_inet6(x INET6) RETURNS INET6
+BEGIN
+DECLARE res INET6 DEFAULT NULL;
+DECLARE CONTINUE HANDLER FOR NOT FOUND
+RETURN res;
+LOOP
+FETCH GROUP NEXT ROW;
+IF (res IS NULL) OR (res > x) THEN
+SET res= x;
+END IF;
+END LOOP;
+END;
+$$
+CREATE OR REPLACE TABLE t1 (name CHAR(30), val INET6);
+INSERT INTO t1 VALUES ('a', '::05');
+INSERT INTO t1 VALUES ('a', '::03');
+INSERT INTO t1 VALUES ('b', '::01');
+INSERT INTO t1 VALUES ('b', '::02');
+INSERT INTO t1 VALUES ('b', '::05');
+SELECT name, aggregate_min_inet6(val) pc FROM t1 GROUP BY name;
+name pc
+a ::3
+b ::1
+CREATE OR REPLACE TABLE t2 (name CHAR(30), val INET6);
+INSERT INTO t2 SELECT name, aggregate_min_inet6(val) pc FROM t1 GROUP BY name;
+SELECT * FROM t2;
+name val
+a ::3
+b ::1
+DROP TABLE t2;
+DROP TABLE t1;
+DROP FUNCTION aggregate_min_inet6;
+#
+# MDEV-20280 PERCENTILE_DISC() rejects temporal and string input
+#
+CREATE TABLE t1 (name CHAR(30), star_rating INET6);
+INSERT INTO t1 VALUES ('Lord of the Ladybirds', '::5');
+INSERT INTO t1 VALUES ('Lord of the Ladybirds', '::3');
+INSERT INTO t1 VALUES ('Lady of the Flies', '::1');
+INSERT INTO t1 VALUES ('Lady of the Flies', '::2');
+INSERT INTO t1 VALUES ('Lady of the Flies', '::5');
+SELECT name, PERCENTILE_DISC(0.5)
+WITHIN GROUP (ORDER BY star_rating)
+OVER (PARTITION BY name) AS pc FROM t1;
+name pc
+Lady of the Flies ::2
+Lady of the Flies ::2
+Lady of the Flies ::2
+Lord of the Ladybirds ::3
+Lord of the Ladybirds ::3
+SELECT name, PERCENTILE_DISC(0)
+WITHIN GROUP (ORDER BY star_rating)
+OVER (PARTITION BY name) AS pc FROM t1;
+name pc
+Lady of the Flies ::1
+Lady of the Flies ::1
+Lady of the Flies ::1
+Lord of the Ladybirds ::3
+Lord of the Ladybirds ::3
+SELECT name, PERCENTILE_DISC(1)
+WITHIN GROUP (ORDER BY star_rating)
+OVER (PARTITION BY name) AS pc FROM t1;
+name pc
+Lady of the Flies ::5
+Lady of the Flies ::5
+Lady of the Flies ::5
+Lord of the Ladybirds ::5
+Lord of the Ladybirds ::5
+DROP TABLE t1;
+#
+# MDEV-22758 Assertion `!item->null_value' failed in Type_handler_inet6::make_sort_key_part
+#
+CREATE TABLE t1 (a VARCHAR(8) NOT NULL, b INET6 NOT NULL);
+INSERT INTO t1 VALUES ('foo','::'),('bar','1::1');
+SELECT * FROM t1 ORDER BY CASE WHEN a THEN b ELSE a END;
+a b
+foo ::
+bar 1::1
+Warnings:
+Warning 1292 Truncated incorrect DOUBLE value: 'foo'
+Warning 1292 Incorrect inet6 value: 'foo'
+Warning 1292 Truncated incorrect DOUBLE value: 'bar'
+Warning 1292 Incorrect inet6 value: 'bar'
+DROP TABLE t1;
+CREATE OR REPLACE TABLE t1 (a VARCHAR(8) NOT NULL);
+INSERT INTO t1 VALUES ('foo'),('bar');
+SELECT * FROM t1 ORDER BY CAST(a AS INET6);
+a
+foo
+bar
+Warnings:
+Warning 1292 Incorrect inet6 value: 'foo'
+Warning 1292 Incorrect inet6 value: 'bar'
+DROP TABLE t1;
+CREATE TABLE t1 (a INET6 NOT NULL, b VARCHAR(32) NOT NULL);
+CREATE TABLE t2 AS SELECT CAST(a AS INET6) AS ca, CAST(b AS INET6) AS cb FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `ca` inet6 NOT NULL,
+ `cb` inet6 DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+CREATE TABLE t2 AS SELECT COALESCE(a,a), COALESCE(a,b) FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `COALESCE(a,a)` inet6 NOT NULL,
+ `COALESCE(a,b)` inet6 DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+CREATE TABLE t2 AS SELECT a AS ca,a AS cb FROM t1 UNION SELECT a,b FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `ca` inet6 NOT NULL DEFAULT '::',
+ `cb` inet6 DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+#
+# MDEV-22758 Assertion `!item->null_value' failed in Type_handler_inet6::make_sort_key_part
+#
+CREATE TABLE t1 (c INET6);
+INSERT INTO t1 VALUES ('::'),(NULL);
+SELECT * FROM t1 ORDER BY IFNULL(c, 'foo');
+c
+NULL
+::
+Warnings:
+Warning 1292 Incorrect inet6 value: 'foo'
+DROP TABLE t1;
+CREATE TABLE t1 (c INET6);
+INSERT INTO t1 VALUES ('::'),(NULL);
+CREATE TABLE t2 AS SELECT IFNULL(c, 'foo') FROM t1;
+Warnings:
+Warning 1292 Incorrect inet6 value: 'foo'
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `IFNULL(c, 'foo')` inet6 DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM t2;
+IFNULL(c, 'foo')
+::
+NULL
+DROP TABLE t2;
+CREATE TABLE t2 AS SELECT IFNULL(c, '::1') FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `IFNULL(c, '::1')` inet6 NOT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM t2;
+IFNULL(c, '::1')
+::
+::1
+DROP TABLE t2;
+DROP TABLE t1;
diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6.test b/plugin/type_inet/mysql-test/type_inet/type_inet6.test
new file mode 100644
index 00000000..ad4cfe57
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/type_inet6.test
@@ -0,0 +1,1588 @@
+
+--echo #
+--echo # Basic CREATE functionality, defaults, metadata
+--echo #
+
+--error ER_WRONG_FIELD_SPEC
+CREATE TABLE t1 (a INET6 AUTO_INCREMENT);
+
+CREATE TABLE t1 (a INET6);
+SHOW CREATE TABLE t1;
+DESCRIBE t1;
+--vertical_results
+--replace_column 19 #
+SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema='test' AND table_name='t1';
+--horizontal_results
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('::1');
+--enable_metadata
+SELECT * FROM t1;
+SELECT CAST('::' AS INET6) AS a;
+--disable_metadata
+DROP TABLE t1;
+
+
+CREATE TABLE t1 (
+ c1 INET6 DEFAULT 0x00000000000000000000000000000000,
+ c2 INET6 DEFAULT 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,
+ c3 INET6 DEFAULT '::',
+ c4 INET6 DEFAULT 'FFFF::ffff',
+ c5 INET6 DEFAULT CAST(X'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' AS INET6)
+);
+SHOW CREATE TABLE t1;
+DESCRIBE t1;
+--vertical_results
+--replace_column 19 #
+SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema='test' AND table_name='t1';
+--horizontal_results
+DROP TABLE t1;
+
+--error ER_INVALID_DEFAULT
+CREATE TABLE t1 (c1 INET6 DEFAULT 0x00);
+--error ER_INVALID_DEFAULT
+CREATE TABLE t1 (c1 INET6 DEFAULT '');
+
+
+CREATE TABLE t1 (a INET6);
+--error ER_TRUNCATED_WRONG_VALUE
+INSERT INTO t1 VALUES ('x');
+--error ER_TRUNCATED_WRONG_VALUE
+INSERT INTO t1 VALUES (1);
+--error ER_TRUNCATED_WRONG_VALUE
+INSERT INTO t1 VALUES (TIME'10:20:30');
+--error ER_TRUNCATED_WRONG_VALUE
+INSERT INTO t1 VALUES (0x00);
+DROP TABLE t1;
+
+--echo #
+--echo # CAST
+--echo #
+
+SELECT CAST('garbage' AS INET6);
+SELECT CAST(0x01 AS INET6);
+SELECT CAST(REPEAT(0x00,16) AS INET6);
+SELECT CAST(REPEAT(0x11,16) AS INET6);
+
+CREATE TABLE t1 AS SELECT CAST('::' AS INET6);
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Text and binary formats, comparison operators
+--echo #
+
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES (0x00000000000000000000000000000000);
+INSERT INTO t1 VALUES (0x00000000000000000000000000000001);
+INSERT INTO t1 VALUES (0xFFFF0000000000000000000000000001);
+INSERT INTO t1 VALUES (0xFFFF0000000000000000000000000002);
+SELECT * FROM t1 ORDER BY a;
+SELECT * FROM t1 ORDER BY a DESC;
+SELECT HEX(a),a FROM t1 ORDER BY a;
+SELECT * FROM t1 WHERE a='::';
+SELECT * FROM t1 WHERE a='::1';
+SELECT * FROM t1 WHERE a='ffff::1';
+SELECT * FROM t1 WHERE a='ffff::2';
+SELECT * FROM t1 WHERE a=0x00000000000000000000000000000000;
+SELECT * FROM t1 WHERE a=0x00000000000000000000000000000001;
+SELECT * FROM t1 WHERE a=0xffff0000000000000000000000000001;
+SELECT * FROM t1 WHERE a=0xffff0000000000000000000000000002;
+SELECT * FROM t1 WHERE a<'::';
+SELECT * FROM t1 WHERE a<='::';
+SELECT * FROM t1 WHERE a>='ffff::2';
+SELECT * FROM t1 WHERE a>'ffff::2';
+SELECT * FROM t1 WHERE a IN ('::', 'ffff::1') ORDER BY a;
+SELECT * FROM t1 WHERE a IN ('::', 0xffff0000000000000000000000000002) ORDER BY a;
+
+SELECT * FROM t1 WHERE a<'garbage';
+SELECT * FROM t1 WHERE a<='garbage';
+SELECT * FROM t1 WHERE a='garbage';
+SELECT * FROM t1 WHERE a>='garbage';
+SELECT * FROM t1 WHERE a>'garbage';
+
+SELECT * FROM t1 WHERE a<0x01;
+SELECT * FROM t1 WHERE a<=0x01;
+SELECT * FROM t1 WHERE a=0x01;
+SELECT * FROM t1 WHERE a>=0x01;
+SELECT * FROM t1 WHERE a>0x01;
+
+SELECT * FROM t1 WHERE a='0::0';
+SELECT * FROM t1 WHERE a='0::00';
+SELECT * FROM t1 WHERE a='0::000';
+SELECT * FROM t1 WHERE a='0::0000';
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT * FROM t1 WHERE a=0;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT * FROM t1 WHERE a=0.0;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT * FROM t1 WHERE a=0e0;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT * FROM t1 WHERE a=TIME'10:20:30';
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT * FROM t1 WHERE a IN ('::', 10);
+
+DROP TABLE t1;
+
+--echo #
+--echo # cmp_item_inet6: IN for non-constants
+--echo #
+
+CREATE TABLE t1 (a INET6, b INET6);
+INSERT INTO t1 VALUES ('::1', '::2');
+SELECT * FROM t1 WHERE '::' IN (a, b);
+SELECT * FROM t1 WHERE '::1' IN (a, b);
+SELECT * FROM t1 WHERE '::01' IN (a, b);
+SELECT * FROM t1 WHERE '00::01' IN (a, b);
+DROP TABLE t1;
+
+
+--echo #
+--echo # cmp_item_inet6: DECODE_ORACLE
+--echo #
+
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES (NULL),('::01'),('::02');
+SELECT a, DECODE_ORACLE(a, '::01', '01') AS d FROM t1;
+SELECT
+ a,
+ DECODE_ORACLE(a, '::01', '01') AS d0,
+ DECODE_ORACLE(a, NULL, '<NULL>', '::01', '01') AS d1,
+ DECODE_ORACLE(a, 'garbage', '<NULL>', '::01', '01') AS d2
+FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # CASE abbreviations
+--echo #
+
+CREATE TABLE t1 (
+ c INET6,
+ c_char CHAR(32),
+ c_varchar VARCHAR(32),
+ c_tinytext TINYTEXT,
+ c_text TEXT,
+ c_mediumtext TEXT,
+ c_longtext LONGTEXT
+);
+CREATE TABLE t2 AS SELECT
+ COALESCE(c, c_char),
+ COALESCE(c, c_varchar),
+ COALESCE(c, c_tinytext),
+ COALESCE(c, c_text),
+ COALESCE(c, c_mediumtext),
+ COALESCE(c, c_longtext)
+FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+CREATE TABLE t2 AS SELECT
+ LEAST(c, c_char),
+ LEAST(c, c_varchar),
+ LEAST(c, c_tinytext),
+ LEAST(c, c_text),
+ LEAST(c, c_mediumtext),
+ LEAST(c, c_longtext)
+FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES (NULL),('::1'),('::2');
+SELECT COALESCE(a, '::') FROM t1 ORDER BY a;
+SELECT a, LEAST(a,'::0'), LEAST(a,'::f') FROM t1 ORDER BY a;
+SELECT a, GREATEST(a,'::0'), GREATEST(a,'::f') FROM t1 ORDER BY a;
+
+CREATE TABLE t2 AS SELECT
+ COALESCE(a, '::'),
+ LEAST(a,'::'),
+ GREATEST(a,'::')
+FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+
+SELECT COALESCE(a, 0x00000000000000000000000000000000) FROM t1 ORDER BY a;
+SELECT a,
+ LEAST(a, 0x00000000000000000000000000000000),
+ LEAST(a, 0x0000000000000000000000000000000f)
+FROM t1 ORDER BY a;
+SELECT a,
+ GREATEST(a, 0x00000000000000000000000000000000),
+ GREATEST(a, 0x0000000000000000000000000000000f)
+FROM t1 ORDER BY a;
+
+CREATE TABLE t2 AS SELECT
+ COALESCE(a, 0x00000000000000000000000000000000),
+ LEAST(a,0x00000000000000000000000000000000),
+ GREATEST(a,0x00000000000000000000000000000000)
+FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT COALESCE(a, 10) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT LEAST(a, 10) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT GREATEST(a, 10) FROM t1;
+DROP TABLE t1;
+
+SELECT COALESCE('garbage', CAST('::1' AS INET6));
+SELECT COALESCE(0x01, CAST('::1' AS INET6));
+
+
+--echo #
+--echo # Uniqueness
+--echo #
+
+CREATE TABLE t1 (a INET6 NOT NULL PRIMARY KEY);
+INSERT INTO t1 VALUES ('41::1'),('61::1');
+--error ER_DUP_ENTRY
+INSERT INTO t1 VALUES ('41::1');
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Indexes
+--echo #
+
+--error ER_WRONG_SUB_KEY
+CREATE TABLE t1 (a INET6, KEY(a(1)));
+
+
+--echo #
+--echo # Explicit CAST on INSERT
+--echo #
+
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES (CAST('1::1' AS INET6));
+INSERT INTO t1 VALUES (CAST('1::2' AS INET6));
+INSERT INTO t1 VALUES (CAST('1::3' AS INET6));
+INSERT INTO t1 VALUES (CAST(CONCAT('2','::1') AS INET6));
+INSERT INTO t1 VALUES (CAST(CONCAT('2','::2') AS INET6));
+INSERT INTO t1 VALUES (CAST(CONCAT('2','::3') AS INET6));
+SELECT * FROM t1 ORDER BY a;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Explicit CAST and implicit CAST on ALTER
+--echo #
+
+CREATE TABLE t1 (a VARCHAR(64));
+INSERT INTO t1 VALUES ('garbage'),('::'),('::1'),('ffff::1'),('ffff::2');
+SELECT a, CAST(a AS INET6) FROM t1 ORDER BY a;
+SELECT a, CAST(a AS INET6) FROM t1 ORDER BY CAST(a AS INET6);
+--error ER_TRUNCATED_WRONG_VALUE
+ALTER TABLE t1 MODIFY a INET6;
+SET sql_mode='';
+ALTER TABLE t1 MODIFY a INET6;
+SET sql_mode=DEFAULT;
+SELECT * FROM t1 ORDER BY a;
+DROP TABLE t1;
+
+
+CREATE TABLE t1 (a BINARY(16));
+INSERT INTO t1 VALUES (0x00000000000000000000000000000000);
+INSERT INTO t1 VALUES (0x00000000000000000000000000000001);
+INSERT INTO t1 VALUES (0xffff0000000000000000000000000001);
+INSERT INTO t1 VALUES (0xffff0000000000000000000000000002);
+SELECT HEX(a), CAST(a AS INET6) FROM t1 ORDER BY a;
+ALTER TABLE t1 MODIFY a INET6;
+SELECT * FROM t1 ORDER BY a;
+DROP TABLE t1;
+
+
+--echo #
+--echo # INSERT..SELECT, same data types
+--echo #
+
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('::'),('::1'),('::2');
+CREATE TABLE t2 (a INET6);
+INSERT INTO t2 SELECT a FROM t1;
+SELECT * FROM t2;
+DROP TABLE t1,t2;
+
+
+--echo #
+--echo # Implicit CAST on INSERT..SELECT, text format
+--echo #
+
+CREATE TABLE t1 (a VARCHAR(64));
+INSERT INTO t1 VALUES ('garbage'),('::'),('::1'),('ffff::1'),('ffff::2');
+
+CREATE TABLE t2 (a INET6);
+--error ER_TRUNCATED_WRONG_VALUE
+INSERT INTO t2 SELECT a FROM t1;
+SET sql_mode='';
+INSERT INTO t2 SELECT a FROM t1;
+SELECT * FROM t2 ORDER BY a;
+SET sql_mode=DEFAULT;
+DROP TABLE t2;
+
+CREATE TABLE t2 (a INET6 NOT NULL);
+--error ER_TRUNCATED_WRONG_VALUE
+INSERT INTO t2 SELECT a FROM t1;
+SET sql_mode='';
+INSERT INTO t2 SELECT a FROM t1;
+SELECT * FROM t2 ORDER BY a;
+SET sql_mode=DEFAULT;
+DROP TABLE t2;
+
+DROP TABLE t1;
+
+
+--echo #
+--echo # Implicit CAST on INSERT..SELECT, binary format
+--echo #
+
+CREATE TABLE t1 (a BINARY(16));
+INSERT INTO t1 VALUES (0x00000000000000000000000000000000);
+INSERT INTO t1 VALUES (0x00000000000000000000000000000001);
+INSERT INTO t1 VALUES (0xffff0000000000000000000000000001);
+INSERT INTO t1 VALUES (0xffff0000000000000000000000000002);
+CREATE TABLE t2 (a INET6);
+INSERT INTO t2 SELECT a FROM t1;
+SELECT a FROM t2 ORDER BY a;
+DROP TABLE t1,t2;
+
+
+--echo #
+--echo # CAST to other data types
+--echo #
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT CAST(CAST('::' AS INET6) AS DOUBLE);
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT CAST(CAST('::' AS INET6) AS FLOAT);
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT CAST(CAST('::' AS INET6) AS DECIMAL);
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT CAST(CAST('::' AS INET6) AS SIGNED);
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT CAST(CAST('::' AS INET6) AS UNSIGNED);
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT CAST(CAST('::' AS INET6) AS TIME);
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT CAST(CAST('::' AS INET6) AS DATE);
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT CAST(CAST('::' AS INET6) AS DATETIME);
+
+SELECT CAST(CAST('::' AS INET6) AS CHAR);
+CREATE TABLE t1 AS SELECT CAST(CAST('::' AS INET6) AS CHAR) AS a;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('ffff::ffff');
+CREATE TABLE t2 AS SELECT
+ CAST(a AS CHAR),
+ CAST(a AS CHAR(39)),
+ CAST(a AS CHAR(530)),
+ CAST(a AS CHAR(65535)),
+ CAST(a AS CHAR(66000)),
+ CAST(a AS CHAR(16777215)),
+ CAST(a AS CHAR(16777216))
+FROM t1;
+SHOW CREATE TABLE t2;
+--vertical_results
+SELECT * FROM t2;
+--horizontal_results
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('ffff::ffff');
+CREATE TABLE t2 AS SELECT
+ CAST(a AS BINARY(4)) AS cb4,
+ CAST(a AS BINARY) AS cb,
+ CAST(a AS BINARY(16)) AS cb16,
+ CAST(a AS BINARY(32)) AS cb32,
+ CAST(a AS BINARY(530)) AS cb530,
+ CAST(a AS BINARY(65535)) AS cb65535,
+ CAST(a AS BINARY(66000)) AS cb66000,
+ CAST(a AS BINARY(16777215)) AS cb16777215,
+ CAST(a AS BINARY(16777216)) AS cb16777216
+FROM t1 LIMIT 0;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+
+CREATE TABLE t2 AS SELECT
+ CAST(a AS BINARY(4)) AS cb4,
+ CAST(a AS BINARY) AS cb,
+ CAST(a AS BINARY(16)) AS cb16,
+ CAST(a AS BINARY(32)) AS cb32,
+ CAST(a AS BINARY(530)) AS cb530,
+ CAST(a AS BINARY(65535)) AS cb65535
+FROM t1;
+SHOW CREATE TABLE t2;
+--vertical_results
+SELECT
+ HEX(cb4),
+ HEX(cb),
+ HEX(cb16),
+ HEX(cb32),
+ LENGTH(cb530),
+ LENGTH(cb65535)
+FROM t2;
+--horizontal_results
+DROP TABLE t2;
+DROP TABLE t1;
+
+--echo #
+--echo # Implicit conversion to other types in INSERT
+--echo #
+
+CREATE TABLE t1 (a INT);
+--error ER_TRUNCATED_WRONG_VALUE_FOR_FIELD
+INSERT INTO t1 VALUES (CAST('::' AS INET6));
+DROP TABLE t1;
+
+CREATE TABLE t1 (a DOUBLE);
+--error ER_TRUNCATED_WRONG_VALUE_FOR_FIELD
+INSERT INTO t1 VALUES (CAST('::' AS INET6));
+DROP TABLE t1;
+
+CREATE TABLE t1 (a DECIMAL(32,0));
+--error ER_TRUNCATED_WRONG_VALUE_FOR_FIELD
+INSERT INTO t1 VALUES (CAST('::' AS INET6));
+DROP TABLE t1;
+
+CREATE TABLE t1 (a VARCHAR(64));
+INSERT INTO t1 VALUES (CAST('::' AS INET6));
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TEXT);
+INSERT INTO t1 VALUES (CAST('::' AS INET6));
+DROP TABLE t1;
+
+
+
+--echo #
+--echo # Boolean context
+--echo #
+
+SELECT
+ CAST('::' AS INET6) IS TRUE,
+ CAST('::' AS INET6) IS FALSE,
+ CAST('::1' AS INET6) IS TRUE,
+ CAST('::1' AS INET6) IS FALSE;
+
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('::'),('::1');
+SELECT a, a IS TRUE, a IS FALSE FROM t1 ORDER BY a;
+DROP TABLE t1;
+
+#
+# TODO: Error looks like a bug. This should return rows where a<>'::'.
+# The same problem is repeatable with GEOMETRY.
+#
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('::'),('::1'),('::2');
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT * FROM t1 WHERE a;
+DROP TABLE t1;
+
+
+--echo #
+--echo # GROUP BY
+--echo #
+
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('::'),('::');
+INSERT INTO t1 VALUES ('::1'),('::01'),('::0001');
+INSERT INTO t1 VALUES ('::2'),('::2'),('::2'),('::2');
+SELECT a, COUNT(*) FROM t1 GROUP BY a;
+DROP TABLE t1;
+
+--echo #
+--echo # Aggregate functions
+--echo #
+
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('::'),('::');
+INSERT INTO t1 VALUES ('::1'),('::01'),('::0001');
+INSERT INTO t1 VALUES ('::2'),('::2'),('::2'),('::2');
+SELECT MIN(a),MAX(a) FROM t1;
+
+CREATE TABLE t2 AS SELECT MIN(a), MAX(a) FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT AVG(a) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT AVG(DISTINCT a) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT SUM(a) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT SUM(DISTINCT a) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT STDDEV(a) FROM t1;
+SELECT GROUP_CONCAT(a ORDER BY a) FROM t1;
+SELECT a, GROUP_CONCAT(a ORDER BY a) FROM t1 GROUP BY a;
+DROP TABLE t1;
+
+--echo #
+--echo # MDEV-21765 Possibly inconsistent behavior of BIT_xx functions with INET6 field
+--echo #
+
+CREATE TABLE t1 (a INET6);
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT BIT_AND(a) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT BIT_OR(a) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT BIT_XOR(a) FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Window functions
+--echo #
+
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('::1'),('::2'),('::3'),('::4');
+SELECT
+ a,
+ LAG(a) OVER (ORDER BY a),
+ LEAD(a) OVER (ORDER BY a)
+FROM t1 ORDER BY a;
+
+SELECT
+ a,
+ FIRST_VALUE(a) OVER (ORDER BY a ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING),
+ LAST_VALUE(a) OVER (ORDER BY a ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)
+FROM t1 ORDER BY a;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Prepared statements
+--echo #
+
+EXECUTE IMMEDIATE 'CREATE TABLE t1 AS SELECT ? AS a' USING CAST('::' AS INET6);
+SHOW CREATE TABLE t1;
+EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES (?)' USING '::1';
+EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES (?)' USING CAST('::2' AS INET6);
+EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES (?)' USING 0x00000000000000000000000000000003;
+SELECT a FROM t1 ORDER BY a;
+EXECUTE IMMEDIATE 'SELECT * FROM t1 WHERE a=?' USING '::1';
+EXECUTE IMMEDIATE 'SELECT * FROM t1 WHERE a=?' USING CAST('::2' AS INET6);
+EXECUTE IMMEDIATE 'SELECT * FROM t1 WHERE a=?' USING 0x00000000000000000000000000000003;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Character set and collation aggregation
+--echo #
+
+CREATE TABLE t1 (a INET6);
+
+CREATE TABLE t2 AS SELECT
+ CONCAT(a) AS c1,
+ CONCAT(CAST('::' AS INET6)) AS c2
+FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+
+CREATE TABLE t2 AS SELECT
+ CONCAT(_utf8'1', a) AS c1,
+ CONCAT(_utf8'1', CAST('::1' AS INET6)) AS c2,
+ CONCAT(_utf8'1', COALESCE(a)) AS c3
+FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+
+CREATE TABLE t2 AS SELECT
+ CONCAT(_latin1'1', a) AS c1,
+ CONCAT(_latin1'1', CAST('::1' AS INET6)) AS c2,
+ CONCAT(_latin1'1', COALESCE(a)) AS c3
+FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+
+DROP TABLE t1;
+
+
+--echo #
+--echo # UNION
+--echo #
+
+CREATE TABLE t1 AS SELECT CAST('::' AS INET6) AS c UNION SELECT CAST('::1' AS INET6);
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 AS SELECT CAST('::' AS INET6) AS c UNION SELECT '::1';
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 AS SELECT '::' AS c UNION SELECT CAST('::1' AS INET6);
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 AS SELECT CAST('::' AS INET6) AS c UNION SELECT 0x00000000000000000000000000000001;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+CREATE TABLE t1 AS SELECT CAST('::' AS INET6) AS c UNION SELECT 1;
+
+
+--echo #
+--echo # Unary operators
+--echo #
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT -CAST('::' AS INET6);
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT ABS(CAST('::' AS INET6));
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT ROUND(CAST('::' AS INET6));
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT CEILING(CAST('::' AS INET6));
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT FLOOR(CAST('::' AS INET6));
+
+
+--echo #
+--echo # Arithmetic operators
+--echo #
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT CAST('::' AS INET6) + 1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT CAST('::' AS INET6) - 1;
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT CAST('::' AS INET6) * 1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT CAST('::' AS INET6) / 1;
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT CAST('::' AS INET6) MOD 1;
+
+
+--echo #
+--echo # Misc
+--echo #
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT RAND(CAST('::' AS INET6));
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT FROM_UNIXTIME(CAST('::' AS INET6));
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT HOUR(CAST('::' AS INET6));
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT YEAR(CAST('::' AS INET6));
+
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT RELEASE_LOCK(CAST('::' AS INET6));
+
+
+SELECT JSON_LENGTH(CAST('::' AS INET6));
+
+--echo #
+--echo # Virtual columns
+--echo #
+
+--error ER_GENERATED_COLUMN_FUNCTION_IS_NOT_ALLOWED
+CREATE TABLE t1 (
+ a INT,
+ b INET6 GENERATED ALWAYS AS (CAST(CONCAT(RAND(),a) AS INET6)), INDEX(b)
+);
+
+CREATE TABLE t1 (
+ a INT,
+ b INET6 GENERATED ALWAYS AS (CAST(CONCAT('::',HEX(a)) AS INET6)), INDEX(b)
+);
+INSERT INTO t1 (a) VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15);
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # VIEW
+--echo #
+
+CREATE TABLE t1 (a INT DEFAULT 0);
+INSERT INTO t1 (a) VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15);
+SELECT * FROM t1 ORDER BY a;
+CREATE VIEW v1 AS SELECT (CAST(CONCAT('::',HEX(a)) AS INET6)) AS c FROM t1;
+SELECT * FROM v1 ORDER BY c;
+DROP VIEW v1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INET6 DEFAULT '::');
+CREATE VIEW v1 AS SELECT * FROM t1;
+SHOW CREATE VIEW v1;
+DESCRIBE v1;
+INSERT INTO v1 VALUES ('::'),('::1'),('::2');
+SELECT * FROM t1;
+DROP VIEW v1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INET6 DEFAULT CAST('::' AS INET6));
+CREATE VIEW v1 AS SELECT * FROM t1;
+SHOW CREATE VIEW v1;
+DESCRIBE v1;
+INSERT INTO v1 VALUES ('::'),('::1'),('::2');
+SELECT * FROM t1;
+DROP VIEW v1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Subqueries
+--echo #
+
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('::'),('::1'),('::2');
+SELECT * FROM t1 WHERE a=(SELECT MIN(a) FROM t1) ORDER BY a;
+SELECT * FROM t1 WHERE a=(SELECT MAX(a) FROM t1) ORDER BY a;
+SELECT * FROM t1 WHERE a IN (SELECT a FROM t1 WHERE a>'::') ORDER BY a;
+DROP TABLE t1;
+
+--echo #
+--echo # Stored routines
+--echo #
+
+DELIMITER $$;
+CREATE PROCEDURE p1(a INET6)
+BEGIN
+ DECLARE b INET6 DEFAULT CONCAT('1', a);
+ SELECT a, b;
+END;
+$$
+DELIMITER ;$$
+CALL p1('::1');
+CALL p1(CAST('::2' AS INET6));
+DROP PROCEDURE p1;
+
+DELIMITER $$;
+CREATE FUNCTION f1(a INET6) RETURNS INET6
+BEGIN
+ RETURN CONCAT('1',a);
+END;
+$$
+DELIMITER ;$$
+SELECT f1('::1');
+SELECT f1(CAST('::1' AS INET6));
+DROP FUNCTION f1;
+
+--echo #
+--echo # Anchored data types in SP variables
+--echo #
+
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('::1');
+DELIMITER $$;
+CREATE PROCEDURE p1()
+BEGIN
+ DECLARE va TYPE OF t1.a;
+ SELECT MAX(a) INTO va FROM t1;
+ SELECT va;
+END;
+$$
+DELIMITER ;$$
+CALL p1;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+CREATE TABLE t1 (a INET6, b INET6);
+INSERT INTO t1 VALUES ('::a', '::b');
+DELIMITER $$;
+CREATE PROCEDURE p1()
+BEGIN
+ DECLARE va ROW TYPE OF t1;
+ SELECT MAX(a), MAX(b) INTO va FROM t1;
+ SELECT va.a, va.b;
+END;
+$$
+DELIMITER ;$$
+CALL p1;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Optimizer: make_const_item_for_comparison
+--echo #
+
+CREATE TABLE t1 (id INT, a INET6);
+INSERT INTO t1 VALUES (1,'::1'),(2,'::2');
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=COALESCE(CAST('::1' AS INET6)) AND id>0;
+DROP TABLE t1;
+
+--echo #
+--echo # Optimizer: equal field propagation
+--echo #
+
+CREATE TABLE t1 (id INT, a INET6);
+INSERT INTO t1 VALUES (1,'::1'),(2,'::2');
+EXPLAIN EXTENDED SELECT * FROM t1
+WHERE a=COALESCE(CAST('::1' AS INET6))
+ AND LENGTH(CONCAT(a,RAND()))>1;
+EXPLAIN EXTENDED SELECT * FROM t1
+WHERE a=COALESCE(CAST('::1' AS INET6))
+ AND LENGTH(a)>1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Optimizer: equal expression propagation
+--echo #
+
+
+CREATE TABLE t1 (id INT, a INET6);
+INSERT INTO t1 VALUES (1,'::1'),(2,'::2');
+EXPLAIN EXTENDED SELECT * FROM t1
+WHERE COALESCE(a)='::1' AND COALESCE(a)=CONCAT(a);
+DROP TABLE t1;
+
+--echo #
+--echo # Subquery materialization
+--echo #
+
+CREATE TABLE t1 (a INET6, b VARCHAR(32), KEY (a), KEY(b)) ;
+INSERT INTO t1 VALUES ('::a','::a'),('::a','::b');
+SET @@optimizer_switch='semijoin=off,materialization=on,in_to_exists=off,subquery_cache=off';
+EXPLAIN SELECT * FROM t1 WHERE a IN (SELECT a AS a_inner FROM t1 GROUP BY a_inner);
+EXPLAIN SELECT * FROM t1 WHERE b IN (SELECT a AS a_inner FROM t1 GROUP BY a_inner);
+SET @@optimizer_switch=DEFAULT;
+DROP TABLE t1;
+
+--echo #
+--echo # IS_IPV4_MAPPED(), IS_IPV4_COMPAT() now understand text notation
+--echo #
+CREATE TABLE t1 (id SERIAL, a VARCHAR(32));
+INSERT INTO t1 (a) VALUES ('::192.168.0.1'),('::192.168.10.111'),('::ffff:10.10.0.1'),('::ffff:192.168.0.1');
+--echo # This is a text notation
+SELECT id, length(a), a, IS_IPV4_MAPPED(a) FROM t1 ORDER BY id;
+SELECT id, length(a), a, IS_IPV4_COMPAT(a) FROM t1 ORDER BY id;
+--echo # This is not a text notation: it is a binary input only looking like text notation
+SELECT id, length(a), a, IS_IPV4_MAPPED(BINARY a) FROM t1 ORDER BY id;
+SELECT id, length(a), a, IS_IPV4_COMPAT(BINARY a) FROM t1 ORDER BY id;
+DROP TABLE t1;
+
+
+--echo #
+--echo # ALTER from INET6 to INET6
+--echo #
+
+CREATE TABLE t1 (a INET6, b INT);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329', 1);
+ALTER TABLE t1 MODIFY b DECIMAL(10,2);
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # ALTER to character string data types
+--echo #
+
+CREATE OR REPLACE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+SELECT CAST(a AS CHAR(39)) FROM t1;
+ALTER TABLE t1 MODIFY a CHAR(39);
+SELECT * FROM t1;
+DROP TABLE t1;
+
+CREATE OR REPLACE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+ALTER TABLE t1 MODIFY a VARCHAR(39);
+SELECT * FROM t1;
+DROP TABLE t1;
+
+CREATE OR REPLACE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+ALTER TABLE t1 MODIFY a TINYTEXT;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+CREATE OR REPLACE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+ALTER TABLE t1 MODIFY a TEXT;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+CREATE OR REPLACE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+ALTER TABLE t1 MODIFY a MEDIUMTEXT;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+CREATE OR REPLACE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+ALTER TABLE t1 MODIFY a LONGTEXT;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # ALTER from character string data types
+--echo #
+
+CREATE OR REPLACE TABLE t1 (a CHAR(64));
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+SELECT CAST(a AS INET6) FROM t1;
+ALTER TABLE t1 MODIFY a INET6;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+CREATE OR REPLACE TABLE t1 (a VARCHAR(64));
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+SELECT CAST(a AS INET6) FROM t1;
+ALTER TABLE t1 MODIFY a INET6;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+CREATE OR REPLACE TABLE t1 (a TINYTEXT);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+SELECT CAST(a AS INET6) FROM t1;
+ALTER TABLE t1 MODIFY a INET6;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+CREATE OR REPLACE TABLE t1 (a TEXT);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+SELECT CAST(a AS INET6) FROM t1;
+ALTER TABLE t1 MODIFY a INET6;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+CREATE OR REPLACE TABLE t1 (a MEDIUMTEXT);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+SELECT CAST(a AS INET6) FROM t1;
+ALTER TABLE t1 MODIFY a INET6;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+CREATE OR REPLACE TABLE t1 (a LONGTEXT);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+SELECT CAST(a AS INET6) FROM t1;
+ALTER TABLE t1 MODIFY a INET6;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # ALTER to binary string data types
+--echo #
+
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+ALTER TABLE t1 MODIFY a BINARY(16);
+SELECT HEX(a) FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+ALTER TABLE t1 MODIFY a BINARY(17);
+SELECT HEX(a) FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+--error ER_DATA_TOO_LONG
+ALTER TABLE t1 MODIFY a BINARY(15);
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+ALTER TABLE t1 MODIFY a TINYBLOB;
+SELECT HEX(a) FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+ALTER TABLE t1 MODIFY a BLOB;
+SELECT HEX(a) FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+ALTER TABLE t1 MODIFY a MEDIUMBLOB;
+SELECT HEX(a) FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+ALTER TABLE t1 MODIFY a LONGBLOB;
+SELECT HEX(a) FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # ALTER from binary string data types
+--echo #
+
+CREATE TABLE t1 (a BINARY(16));
+INSERT INTO t1 VALUES (X'20010DB8000000000000FF0000428329');
+ALTER TABLE t1 MODIFY a INET6;
+SELECT a FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a BINARY(17));
+INSERT INTO t1 VALUES (X'20010DB8000000000000FF000042832900');
+--error ER_TRUNCATED_WRONG_VALUE
+ALTER TABLE t1 MODIFY a INET6;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a BINARY(15));
+INSERT INTO t1 VALUES (X'20010DB8000000000000FF00004283');
+--error ER_TRUNCATED_WRONG_VALUE
+ALTER TABLE t1 MODIFY a INET6;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TINYBLOB);
+INSERT INTO t1 VALUES (X'20010DB8000000000000FF0000428329');
+ALTER TABLE t1 MODIFY a INET6;
+SELECT a FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a BLOB);
+INSERT INTO t1 VALUES (X'20010DB8000000000000FF0000428329');
+ALTER TABLE t1 MODIFY a INET6;
+SELECT a FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a MEDIUMBLOB);
+INSERT INTO t1 VALUES (X'20010DB8000000000000FF0000428329');
+ALTER TABLE t1 MODIFY a INET6;
+SELECT a FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a BLOB);
+INSERT INTO t1 VALUES (X'20010DB8000000000000FF0000428329');
+ALTER TABLE t1 MODIFY a INET6;
+SELECT a FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # SET from INET6 to INET6
+--echo #
+
+CREATE TABLE t1 (a INET6, b INET6);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # SET from INET6 to numeric
+--echo #
+
+CREATE TABLE t1 (a INET6, b INT);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+--error ER_TRUNCATED_WRONG_VALUE_FOR_FIELD
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INET6, b DOUBLE);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+--error ER_TRUNCATED_WRONG_VALUE_FOR_FIELD
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INET6, b DECIMAL(32,0));
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+--error ER_TRUNCATED_WRONG_VALUE_FOR_FIELD
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INET6, b YEAR);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+--error ER_TRUNCATED_WRONG_VALUE_FOR_FIELD
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # SET from numeric to INET6
+--echo #
+
+CREATE TABLE t1 (a INT, b INET6);
+INSERT INTO t1 VALUES (1, NULL);
+--error ER_TRUNCATED_WRONG_VALUE
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a DOUBLE, b INET6);
+INSERT INTO t1 VALUES (1, NULL);
+--error ER_TRUNCATED_WRONG_VALUE
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a DECIMAL(32,0), b INET6);
+INSERT INTO t1 VALUES (1, NULL);
+--error ER_TRUNCATED_WRONG_VALUE
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a YEAR, b INET6);
+INSERT INTO t1 VALUES (1, NULL);
+--error ER_TRUNCATED_WRONG_VALUE
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # SET from INET6 to temporal
+--echo #
+
+CREATE TABLE t1 (a INET6, b TIME);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+--error ER_TRUNCATED_WRONG_VALUE
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INET6, b DATE);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+--error ER_TRUNCATED_WRONG_VALUE
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INET6, b DATETIME);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+--error ER_TRUNCATED_WRONG_VALUE
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INET6, b TIMESTAMP NULL DEFAULT NULL);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+--error ER_TRUNCATED_WRONG_VALUE
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # SET from temporal to INET6
+--echo #
+
+CREATE TABLE t1 (a TIME, b INET6);
+INSERT INTO t1 VALUES ('00:00:00', NULL);
+--error ER_TRUNCATED_WRONG_VALUE
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a DATE, b INET6);
+INSERT INTO t1 VALUES ('2001-01:01', NULL);
+--error ER_TRUNCATED_WRONG_VALUE
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a DATETIME, b INET6);
+INSERT INTO t1 VALUES ('2001-01-01 10:20:30', NULL);
+--error ER_TRUNCATED_WRONG_VALUE
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TIMESTAMP, b INET6);
+INSERT INTO t1 VALUES ('2001-01-01 10:20:30', NULL);
+--error ER_TRUNCATED_WRONG_VALUE
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # SET from INET6 to character string
+--echo #
+
+CREATE TABLE t1 (a INET6, b CHAR(39));
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INET6, b VARCHAR(39));
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INET6, b TEXT);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INET6, b ENUM('ffff::ffff'));
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INET6, b SET('ffff::ffff'));
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # SET from character string to INET6
+--echo #
+
+CREATE TABLE t1 (a CHAR(39), b INET6);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a VARCHAR(39), b INET6);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TEXT, b INET6);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a ENUM('ffff::ffff'), b INET6);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a SET('ffff::ffff'), b INET6);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # SET from INET6 to binary
+--echo #
+
+CREATE TABLE t1 (a INET6, b BINARY(16));
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT HEX(b) FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INET6, b VARBINARY(39));
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT HEX(b) FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INET6, b BLOB);
+INSERT INTO t1 VALUES ('ffff::ffff', NULL);
+UPDATE t1 SET b=a;
+SELECT HEX(b) FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # SET from binary to INET6
+--echo #
+
+CREATE TABLE t1 (a BINARY(16), b INET6);
+INSERT INTO t1 VALUES (CONCAT(0xFFFF,REPEAT(0x0000,6),0xFFFF), NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a VARBINARY(16), b INET6);
+INSERT INTO t1 VALUES (CONCAT(0xFFFF,REPEAT(0x0000,6),0xFFFF), NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a BLOB, b INET6);
+INSERT INTO t1 VALUES (CONCAT(0xFFFF,REPEAT(0x0000,6),0xFFFF), NULL);
+UPDATE t1 SET b=a;
+SELECT b FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Limit clause parameter
+--echo # TODO: this should fail.
+--echo # The test for a valid data type should be moved
+--echo # from parse time to fix_fields() time, and performed
+--echo # for both Item_splocal and Item_param.
+--echo #
+
+EXECUTE IMMEDIATE 'SELECT 1 FROM DUAL LIMIT ?' USING CAST('::' AS INET6);
+
+
+## TODO:
+## - Add hooks to run mysql_client_test with pluggable data types
+##
+## - This should fail with the "illegal data type" error:
+##SELECT CAST('::' AS INET6) DIV 1;
+##
+## - This should fail with the "illegal data type" error:
+## EXTRACT(MINUTE...)
+##
+
+
+--echo #
+--echo # MDEV-20785 Converting INET6 to CHAR(39) produces garbage without a warning
+--echo #
+
+CREATE OR REPLACE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+SELECT CAST(a AS CHAR(39)) FROM t1;
+ALTER TABLE t1 MODIFY a CHAR(39);
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # MDEV-20783 INET6 cannot be converted to BINARY(16) (requires clarification in documentation)
+--echo #
+
+CREATE OR REPLACE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+ALTER TABLE t1 MODIFY a BINARY(16);
+SELECT HEX(a) FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # MDEV-20795 CAST(inet6 AS BINARY) returns wrong result
+--echo #
+
+CREATE OR REPLACE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+SELECT HEX(CAST(a AS BINARY)) FROM t1;
+SELECT HEX(CAST(a AS BINARY(16))) FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # MDEV-20808 CAST from INET6 to FLOAT does not produce an error
+--echo #
+
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('::');
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT CAST(a AS FLOAT) FROM t1;
+DROP TABLE t1;
+
+--echo #
+--echo # MDEV-20798 Conversion from INET6 to other types performed without errors or warnings
+--echo #
+
+CREATE TABLE t1 (a INET6, b INT);
+INSERT INTO t1 (a) VALUES ('::');
+--error ER_TRUNCATED_WRONG_VALUE_FOR_FIELD
+UPDATE t1 SET b=a;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+SET timestamp=UNIX_TIMESTAMP('2001-01-01 10:20:30');
+CREATE TABLE t1 (a INET6, b TIMESTAMP);
+INSERT INTO t1 (a) VALUES ('::');
+--error ER_TRUNCATED_WRONG_VALUE
+UPDATE t1 SET b=a;
+SELECT * FROM t1;
+DROP TABLE t1;
+SET timestamp=DEFAULT;
+
+CREATE OR REPLACE TABLE t1 (a INET6);
+INSERT INTO t1 (a) VALUES ('::');
+--error ER_TRUNCATED_WRONG_VALUE
+ALTER TABLE t1 MODIFY a DATE;
+DROP TABLE t1;
+
+--echo #
+--echo # MDEV-20818 ER_CRASHED_ON_USAGE or Assertion `length <= column->length' failed in write_block_record on temporary table
+--echo #
+
+CREATE TABLE t1 (a INET6);
+--enable_metadata
+SELECT
+ CAST(a AS BINARY(0)),
+ CAST(a AS BINARY(1)),
+ CAST(a AS BINARY(16)),
+ CAST(a AS BINARY(255)),
+ CAST(a AS BINARY(256)),
+ CAST(a AS BINARY(512)),
+ CAST(a AS BINARY(513)),
+ CAST(a AS BINARY(65532)),
+ CAST(a AS BINARY(65533)),
+ CAST(a AS BINARY(65534)),
+ CAST(a AS BINARY(65535)),
+ CAST(a AS BINARY(65536)),
+ CAST(a AS BINARY(16777215)),
+ CAST(a AS BINARY(16777216))
+FROM t1;
+--disable_metadata
+DROP TABLE t1;
+
+--echo #
+--echo # MDEV-20826 Wrong result of MIN(inet6) with GROUP BY
+--echo #
+
+CREATE TABLE t1 (id INT, a INET6) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (1, 'fff::'),(1, '8888::');
+SELECT MIN(a), MAX(a) FROM t1 GROUP BY id;
+DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-20809 EXTRACT from INET6 value does not produce any warnings
+--echo #
+
+CREATE TABLE t1 (a INET6);
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT EXTRACT(DAY FROM a) FROM t1;
+DROP TABLE t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
+SELECT EXTRACT(DAY FROM CAST('::' AS INET6));
+
+
+--echo #
+--echo # MDEV-22764 Crash with a stored aggregate function returning INET6
+--echo #
+
+DELIMITER $$;
+CREATE OR REPLACE AGGREGATE FUNCTION aggregate_min_inet6(x INET6) RETURNS INET6
+BEGIN
+ DECLARE res INET6 DEFAULT NULL;
+ DECLARE CONTINUE HANDLER FOR NOT FOUND
+ RETURN res;
+ LOOP
+ FETCH GROUP NEXT ROW;
+ IF (res IS NULL) OR (res > x) THEN
+ SET res= x;
+ END IF;
+ END LOOP;
+END;
+$$
+DELIMITER ;$$
+
+CREATE OR REPLACE TABLE t1 (name CHAR(30), val INET6);
+INSERT INTO t1 VALUES ('a', '::05');
+INSERT INTO t1 VALUES ('a', '::03');
+INSERT INTO t1 VALUES ('b', '::01');
+INSERT INTO t1 VALUES ('b', '::02');
+INSERT INTO t1 VALUES ('b', '::05');
+SELECT name, aggregate_min_inet6(val) pc FROM t1 GROUP BY name;
+
+CREATE OR REPLACE TABLE t2 (name CHAR(30), val INET6);
+INSERT INTO t2 SELECT name, aggregate_min_inet6(val) pc FROM t1 GROUP BY name;
+SELECT * FROM t2;
+DROP TABLE t2;
+
+DROP TABLE t1;
+DROP FUNCTION aggregate_min_inet6;
+
+
+--echo #
+--echo # MDEV-20280 PERCENTILE_DISC() rejects temporal and string input
+--echo #
+
+CREATE TABLE t1 (name CHAR(30), star_rating INET6);
+INSERT INTO t1 VALUES ('Lord of the Ladybirds', '::5');
+INSERT INTO t1 VALUES ('Lord of the Ladybirds', '::3');
+INSERT INTO t1 VALUES ('Lady of the Flies', '::1');
+INSERT INTO t1 VALUES ('Lady of the Flies', '::2');
+INSERT INTO t1 VALUES ('Lady of the Flies', '::5');
+SELECT name, PERCENTILE_DISC(0.5)
+ WITHIN GROUP (ORDER BY star_rating)
+ OVER (PARTITION BY name) AS pc FROM t1;
+SELECT name, PERCENTILE_DISC(0)
+ WITHIN GROUP (ORDER BY star_rating)
+ OVER (PARTITION BY name) AS pc FROM t1;
+SELECT name, PERCENTILE_DISC(1)
+ WITHIN GROUP (ORDER BY star_rating)
+ OVER (PARTITION BY name) AS pc FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # MDEV-22758 Assertion `!item->null_value' failed in Type_handler_inet6::make_sort_key_part
+--echo #
+
+CREATE TABLE t1 (a VARCHAR(8) NOT NULL, b INET6 NOT NULL);
+INSERT INTO t1 VALUES ('foo','::'),('bar','1::1');
+SELECT * FROM t1 ORDER BY CASE WHEN a THEN b ELSE a END;
+DROP TABLE t1;
+
+CREATE OR REPLACE TABLE t1 (a VARCHAR(8) NOT NULL);
+INSERT INTO t1 VALUES ('foo'),('bar');
+SELECT * FROM t1 ORDER BY CAST(a AS INET6);
+DROP TABLE t1;
+
+CREATE TABLE t1 (a INET6 NOT NULL, b VARCHAR(32) NOT NULL);
+CREATE TABLE t2 AS SELECT CAST(a AS INET6) AS ca, CAST(b AS INET6) AS cb FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+
+CREATE TABLE t2 AS SELECT COALESCE(a,a), COALESCE(a,b) FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+
+CREATE TABLE t2 AS SELECT a AS ca,a AS cb FROM t1 UNION SELECT a,b FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+
+DROP TABLE t1;
+
+--echo #
+--echo # MDEV-22758 Assertion `!item->null_value' failed in Type_handler_inet6::make_sort_key_part
+--echo #
+
+CREATE TABLE t1 (c INET6);
+INSERT INTO t1 VALUES ('::'),(NULL);
+SELECT * FROM t1 ORDER BY IFNULL(c, 'foo');
+DROP TABLE t1;
+
+CREATE TABLE t1 (c INET6);
+INSERT INTO t1 VALUES ('::'),(NULL);
+
+# Expect a NULL column
+CREATE TABLE t2 AS SELECT IFNULL(c, 'foo') FROM t1;
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t2;
+
+# Expect a NOT NULL column
+CREATE TABLE t2 AS SELECT IFNULL(c, '::1') FROM t1;
+SHOW CREATE TABLE t2;
+SELECT * FROM t2;
+DROP TABLE t2;
+
+DROP TABLE t1;
diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_csv.result b/plugin/type_inet/mysql-test/type_inet/type_inet6_csv.result
new file mode 100644
index 00000000..8e972235
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_csv.result
@@ -0,0 +1,70 @@
+#
+# Start of 10.5 tests
+#
+#
+# MDEV-274 The data type for IPv6/IPv4 addresses in MariaDB
+#
+SET default_storage_engine=CSV;
+CREATE TABLE t1 (a INET6 NOT NULL);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` inet6 NOT NULL
+) ENGINE=CSV DEFAULT CHARSET=latin1
+FOR i IN 0..255
+DO
+INSERT INTO t1 VALUES (CONCAT('::', HEX(i)));
+END FOR
+$$
+SELECT * FROM t1 WHERE a='::ff';
+a
+::ff
+SELECT * FROM t1 WHERE a>='::fe' ORDER BY a;
+a
+::fe
+::ff
+SELECT * FROM t1 WHERE a IN ('::80','::a0','::f0') ORDER BY a;
+a
+::80
+::a0
+::f0
+SELECT * FROM t1 WHERE a BETWEEN '::80' AND '::81' ORDER BY a;
+a
+::80
+::81
+SELECT * FROM t1 WHERE a=CAST('::ff' AS INET6);
+a
+::ff
+UPDATE t1 SET a=CONCAT('ffff', a) WHERE a LIKE '::a%';
+SELECT * FROM t1 WHERE a LIKE 'ffff::%' ORDER BY a;
+a
+ffff::a
+ffff::a0
+ffff::a1
+ffff::a2
+ffff::a3
+ffff::a4
+ffff::a5
+ffff::a6
+ffff::a7
+ffff::a8
+ffff::a9
+ffff::aa
+ffff::ab
+ffff::ac
+ffff::ad
+ffff::ae
+ffff::af
+DROP TABLE t1;
+#
+# MDEV-20790 CSV table with INET6 can be created and inserted into, but cannot be read from
+#
+CREATE TABLE t1 (a INET6 NOT NULL) ENGINE=CSV;
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+SELECT * FROM t1;
+a
+2001:db8::ff00:42:8329
+DROP TABLE t1;
+#
+# End of 10.5 tests
+#
diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_csv.test b/plugin/type_inet/mysql-test/type_inet/type_inet6_csv.test
new file mode 100644
index 00000000..65761cf0
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_csv.test
@@ -0,0 +1,51 @@
+--source include/have_csv.inc
+
+--echo #
+--echo # Start of 10.5 tests
+--echo #
+
+--echo #
+--echo # MDEV-274 The data type for IPv6/IPv4 addresses in MariaDB
+--echo #
+
+SET default_storage_engine=CSV;
+
+CREATE TABLE t1 (a INET6 NOT NULL);
+SHOW CREATE TABLE t1;
+
+DELIMITER $$;
+FOR i IN 0..255
+DO
+ INSERT INTO t1 VALUES (CONCAT('::', HEX(i)));
+END FOR
+$$
+DELIMITER ;$$
+
+SELECT * FROM t1 WHERE a='::ff';
+
+SELECT * FROM t1 WHERE a>='::fe' ORDER BY a;
+
+SELECT * FROM t1 WHERE a IN ('::80','::a0','::f0') ORDER BY a;
+
+SELECT * FROM t1 WHERE a BETWEEN '::80' AND '::81' ORDER BY a;
+
+SELECT * FROM t1 WHERE a=CAST('::ff' AS INET6);
+
+UPDATE t1 SET a=CONCAT('ffff', a) WHERE a LIKE '::a%';
+SELECT * FROM t1 WHERE a LIKE 'ffff::%' ORDER BY a;
+
+DROP TABLE t1;
+
+--echo #
+--echo # MDEV-20790 CSV table with INET6 can be created and inserted into, but cannot be read from
+--echo #
+
+CREATE TABLE t1 (a INET6 NOT NULL) ENGINE=CSV;
+INSERT INTO t1 VALUES ('2001:db8::ff00:42:8329');
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # End of 10.5 tests
+--echo #
diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_engines.inc b/plugin/type_inet/mysql-test/type_inet/type_inet6_engines.inc
new file mode 100644
index 00000000..596036fc
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_engines.inc
@@ -0,0 +1,38 @@
+--echo #
+--echo # Range optimizer
+--echo #
+
+CREATE TABLE t1 (a INET6, INDEX(a));
+SHOW CREATE TABLE t1;
+
+DELIMITER $$;
+FOR i IN 0..255
+DO
+ INSERT INTO t1 VALUES (CONCAT('::', HEX(i)));
+END FOR
+$$
+DELIMITER ;$$
+SELECT * FROM t1 WHERE a='::ff';
+EXPLAIN SELECT * FROM t1 WHERE a='::ff';
+SELECT * FROM t1 WHERE a='garbage';
+EXPLAIN SELECT * FROM t1 WHERE a='garbage';
+
+SELECT * FROM t1 WHERE a>='::fe';
+EXPLAIN SELECT * FROM t1 WHERE a>='::fe';
+SELECT * FROM t1 WHERE a>='garbage';
+EXPLAIN SELECT * FROM t1 WHERE a>='garbage';
+
+SELECT * FROM t1 WHERE a IN ('::80','::a0','::f0');
+EXPLAIN SELECT * FROM t1 WHERE a IN ('::80','::a0','::f0');
+SELECT * FROM t1 WHERE a IN ('::80','::a0','garbage');
+EXPLAIN SELECT * FROM t1 WHERE a IN ('::80','::a0','garbage');
+
+SELECT * FROM t1 WHERE a BETWEEN '::80' AND '::81';
+EXPLAIN SELECT * FROM t1 WHERE a BETWEEN '::80' AND '::81';
+SELECT * FROM t1 WHERE a BETWEEN '::80' AND 'garbage';
+EXPLAIN SELECT * FROM t1 WHERE a BETWEEN '::80' AND 'garbage';
+
+SELECT * FROM t1 WHERE a=CAST('::ff' AS INET6);
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=CAST('::ff' AS INET6);
+
+DROP TABLE t1;
diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_innodb.result b/plugin/type_inet/mysql-test/type_inet/type_inet6_innodb.result
new file mode 100644
index 00000000..5f7063b8
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_innodb.result
@@ -0,0 +1,92 @@
+#
+# Start of 10.5 tests
+#
+#
+# MDEV-274 The data type for IPv6/IPv4 addresses in MariaDB
+#
+SET default_storage_engine=InnoDB;
+#
+# Range optimizer
+#
+CREATE TABLE t1 (a INET6, INDEX(a));
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` inet6 DEFAULT NULL,
+ KEY `a` (`a`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+FOR i IN 0..255
+DO
+INSERT INTO t1 VALUES (CONCAT('::', HEX(i)));
+END FOR
+$$
+SELECT * FROM t1 WHERE a='::ff';
+a
+::ff
+EXPLAIN SELECT * FROM t1 WHERE a='::ff';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref a a 17 const 1 Using where; Using index
+SELECT * FROM t1 WHERE a='garbage';
+a
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage'
+EXPLAIN SELECT * FROM t1 WHERE a='garbage';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage'
+SELECT * FROM t1 WHERE a>='::fe';
+a
+::fe
+::ff
+EXPLAIN SELECT * FROM t1 WHERE a>='::fe';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 17 NULL 2 Using where; Using index
+SELECT * FROM t1 WHERE a>='garbage';
+a
+EXPLAIN SELECT * FROM t1 WHERE a>='garbage';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+SELECT * FROM t1 WHERE a IN ('::80','::a0','::f0');
+a
+::80
+::a0
+::f0
+EXPLAIN SELECT * FROM t1 WHERE a IN ('::80','::a0','::f0');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 17 NULL 3 Using where; Using index
+SELECT * FROM t1 WHERE a IN ('::80','::a0','garbage');
+a
+::80
+::a0
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage'
+EXPLAIN SELECT * FROM t1 WHERE a IN ('::80','::a0','garbage');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 17 NULL 2 Using where; Using index
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage'
+SELECT * FROM t1 WHERE a BETWEEN '::80' AND '::81';
+a
+::80
+::81
+EXPLAIN SELECT * FROM t1 WHERE a BETWEEN '::80' AND '::81';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 17 NULL 2 Using where; Using index
+SELECT * FROM t1 WHERE a BETWEEN '::80' AND 'garbage';
+a
+EXPLAIN SELECT * FROM t1 WHERE a BETWEEN '::80' AND 'garbage';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+SELECT * FROM t1 WHERE a=CAST('::ff' AS INET6);
+a
+::ff
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=CAST('::ff' AS INET6);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ref a a 17 const 1 100.00 Using where; Using index
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = INET6'::ff'
+DROP TABLE t1;
+#
+# End of 10.5 tests
+#
diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_innodb.test b/plugin/type_inet/mysql-test/type_inet/type_inet6_innodb.test
new file mode 100644
index 00000000..dd6049ab
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_innodb.test
@@ -0,0 +1,18 @@
+--source include/have_innodb.inc
+
+--echo #
+--echo # Start of 10.5 tests
+--echo #
+
+--echo #
+--echo # MDEV-274 The data type for IPv6/IPv4 addresses in MariaDB
+--echo #
+
+
+SET default_storage_engine=InnoDB;
+--source type_inet6_engines.inc
+
+
+--echo #
+--echo # End of 10.5 tests
+--echo #
diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_memory.result b/plugin/type_inet/mysql-test/type_inet/type_inet6_memory.result
new file mode 100644
index 00000000..db419636
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_memory.result
@@ -0,0 +1,159 @@
+#
+# Start of 10.5 tests
+#
+#
+# MDEV-274 The data type for IPv6/IPv4 addresses in MariaDB
+#
+SET default_storage_engine=MEMORY;
+#
+# Range optimizer
+#
+CREATE TABLE t1 (a INET6, INDEX(a));
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` inet6 DEFAULT NULL,
+ KEY `a` (`a`)
+) ENGINE=MEMORY DEFAULT CHARSET=latin1
+FOR i IN 0..255
+DO
+INSERT INTO t1 VALUES (CONCAT('::', HEX(i)));
+END FOR
+$$
+SELECT * FROM t1 WHERE a='::ff';
+a
+::ff
+EXPLAIN SELECT * FROM t1 WHERE a='::ff';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref a a 17 const 2 Using where
+SELECT * FROM t1 WHERE a='garbage';
+a
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage'
+EXPLAIN SELECT * FROM t1 WHERE a='garbage';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage'
+SELECT * FROM t1 WHERE a>='::fe';
+a
+::fe
+::ff
+EXPLAIN SELECT * FROM t1 WHERE a>='::fe';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL a NULL NULL NULL 256 Using where
+SELECT * FROM t1 WHERE a>='garbage';
+a
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage'
+EXPLAIN SELECT * FROM t1 WHERE a>='garbage';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL a NULL NULL NULL 256 Using where
+SELECT * FROM t1 WHERE a IN ('::80','::a0','::f0');
+a
+::80
+::a0
+::f0
+EXPLAIN SELECT * FROM t1 WHERE a IN ('::80','::a0','::f0');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 17 NULL 6 Using where
+SELECT * FROM t1 WHERE a IN ('::80','::a0','garbage');
+a
+::80
+::a0
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage'
+EXPLAIN SELECT * FROM t1 WHERE a IN ('::80','::a0','garbage');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 17 NULL 4 Using where
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage'
+SELECT * FROM t1 WHERE a BETWEEN '::80' AND '::81';
+a
+::80
+::81
+EXPLAIN SELECT * FROM t1 WHERE a BETWEEN '::80' AND '::81';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL a NULL NULL NULL 256 Using where
+SELECT * FROM t1 WHERE a BETWEEN '::80' AND 'garbage';
+a
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+Warning 1292 Incorrect inet6 value: 'garbage'
+EXPLAIN SELECT * FROM t1 WHERE a BETWEEN '::80' AND 'garbage';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL a NULL NULL NULL 256 Using where
+SELECT * FROM t1 WHERE a=CAST('::ff' AS INET6);
+a
+::ff
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=CAST('::ff' AS INET6);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ref a a 17 const 2 100.00 Using where
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = INET6'::ff'
+DROP TABLE t1;
+#
+# End of 10.5 tests
+#
diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_memory.test b/plugin/type_inet/mysql-test/type_inet/type_inet6_memory.test
new file mode 100644
index 00000000..da3f8389
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_memory.test
@@ -0,0 +1,16 @@
+--echo #
+--echo # Start of 10.5 tests
+--echo #
+
+--echo #
+--echo # MDEV-274 The data type for IPv6/IPv4 addresses in MariaDB
+--echo #
+
+
+SET default_storage_engine=MEMORY;
+--source type_inet6_engines.inc
+
+
+--echo #
+--echo # End of 10.5 tests
+--echo #
diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_myisam.result b/plugin/type_inet/mysql-test/type_inet/type_inet6_myisam.result
new file mode 100644
index 00000000..c8dba6ff
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_myisam.result
@@ -0,0 +1,92 @@
+#
+# Start of 10.5 tests
+#
+#
+# MDEV-274 The data type for IPv6/IPv4 addresses in MariaDB
+#
+SET default_storage_engine=MyISAM;
+#
+# Range optimizer
+#
+CREATE TABLE t1 (a INET6, INDEX(a));
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` inet6 DEFAULT NULL,
+ KEY `a` (`a`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+FOR i IN 0..255
+DO
+INSERT INTO t1 VALUES (CONCAT('::', HEX(i)));
+END FOR
+$$
+SELECT * FROM t1 WHERE a='::ff';
+a
+::ff
+EXPLAIN SELECT * FROM t1 WHERE a='::ff';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref a a 17 const 1 Using where; Using index
+SELECT * FROM t1 WHERE a='garbage';
+a
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage'
+EXPLAIN SELECT * FROM t1 WHERE a='garbage';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage'
+SELECT * FROM t1 WHERE a>='::fe';
+a
+::fe
+::ff
+EXPLAIN SELECT * FROM t1 WHERE a>='::fe';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 17 NULL 2 Using where; Using index
+SELECT * FROM t1 WHERE a>='garbage';
+a
+EXPLAIN SELECT * FROM t1 WHERE a>='garbage';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+SELECT * FROM t1 WHERE a IN ('::80','::a0','::f0');
+a
+::80
+::a0
+::f0
+EXPLAIN SELECT * FROM t1 WHERE a IN ('::80','::a0','::f0');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 17 NULL 3 Using where; Using index
+SELECT * FROM t1 WHERE a IN ('::80','::a0','garbage');
+a
+::80
+::a0
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage'
+EXPLAIN SELECT * FROM t1 WHERE a IN ('::80','::a0','garbage');
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 17 NULL 2 Using where; Using index
+Warnings:
+Warning 1292 Incorrect inet6 value: 'garbage'
+SELECT * FROM t1 WHERE a BETWEEN '::80' AND '::81';
+a
+::80
+::81
+EXPLAIN SELECT * FROM t1 WHERE a BETWEEN '::80' AND '::81';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range a a 17 NULL 2 Using where; Using index
+SELECT * FROM t1 WHERE a BETWEEN '::80' AND 'garbage';
+a
+EXPLAIN SELECT * FROM t1 WHERE a BETWEEN '::80' AND 'garbage';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+SELECT * FROM t1 WHERE a=CAST('::ff' AS INET6);
+a
+::ff
+EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=CAST('::ff' AS INET6);
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE t1 ref a a 17 const 1 100.00 Using where; Using index
+Warnings:
+Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = INET6'::ff'
+DROP TABLE t1;
+#
+# End of 10.5 tests
+#
diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_myisam.test b/plugin/type_inet/mysql-test/type_inet/type_inet6_myisam.test
new file mode 100644
index 00000000..c5183f01
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_myisam.test
@@ -0,0 +1,16 @@
+--echo #
+--echo # Start of 10.5 tests
+--echo #
+
+--echo #
+--echo # MDEV-274 The data type for IPv6/IPv4 addresses in MariaDB
+--echo #
+
+
+SET default_storage_engine=MyISAM;
+--source type_inet6_engines.inc
+
+
+--echo #
+--echo # End of 10.5 tests
+--echo #
diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_mysql.result b/plugin/type_inet/mysql-test/type_inet/type_inet6_mysql.result
new file mode 100644
index 00000000..868b9902
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_mysql.result
@@ -0,0 +1,39 @@
+CREATE TABLE t1 (a INET6);
+Field 1: `a`
+Catalog: `def`
+Database: `test`
+Table: `t1`
+Org_table: `t1`
+Type: STRING (type=inet6)
+Collation: latin1_swedish_ci (8)
+Length: 39
+Max_length: 0
+Decimals: 0
+Flags: UNSIGNED BINARY
+
+Field 2: `b`
+Catalog: `def`
+Database: ``
+Table: ``
+Org_table: ``
+Type: STRING (type=inet6)
+Collation: latin1_swedish_ci (8)
+Length: 39
+Max_length: 0
+Decimals: 0
+Flags: NOT_NULL UNSIGNED
+
+Field 3: `c`
+Catalog: `def`
+Database: ``
+Table: ``
+Org_table: ``
+Type: STRING (type=inet6)
+Collation: latin1_swedish_ci (8)
+Length: 39
+Max_length: 0
+Decimals: 0
+Flags: UNSIGNED
+
+
+DROP TABLE t1;
diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_mysql.test b/plugin/type_inet/mysql-test/type_inet/type_inet6_mysql.test
new file mode 100644
index 00000000..dfb30081
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_mysql.test
@@ -0,0 +1,6 @@
+-- source include/have_working_dns.inc
+-- source include/not_embedded.inc
+
+CREATE TABLE t1 (a INET6);
+--exec $MYSQL -t test --column-type-info -e "SELECT a, CAST('::' AS INET6) AS b, COALESCE(a) AS c FROM t1" 2>&1
+DROP TABLE t1;
diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_oracle.result b/plugin/type_inet/mysql-test/type_inet/type_inet6_oracle.result
new file mode 100644
index 00000000..8b041e45
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_oracle.result
@@ -0,0 +1,29 @@
+#
+# Start of 10.5 tests
+#
+#
+# MDEV-20913 sql_mode=ORACLE: INET6 does not work as a routine parameter type and return type
+#
+SET sql_mode=ORACLE;
+CREATE OR REPLACE FUNCTION f1() RETURN INET6 AS
+BEGIN
+RETURN 'ffff::ffff';
+END;
+$$
+SELECT f1();
+f1()
+ffff::ffff
+DROP FUNCTION f1;
+SET sql_mode=ORACLE;
+CREATE OR REPLACE FUNCTION f1(a INET6) RETURN INT AS
+BEGIN
+RETURN LENGTH(a);
+END;
+$$
+SELECT f1('0::0');
+f1('0::0')
+2
+DROP FUNCTION f1;
+#
+# End of 10.5 tests
+#
diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_oracle.test b/plugin/type_inet/mysql-test/type_inet/type_inet6_oracle.test
new file mode 100644
index 00000000..46754bf9
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_oracle.test
@@ -0,0 +1,35 @@
+--echo #
+--echo # Start of 10.5 tests
+--echo #
+
+--echo #
+--echo # MDEV-20913 sql_mode=ORACLE: INET6 does not work as a routine parameter type and return type
+--echo #
+
+SET sql_mode=ORACLE;
+DELIMITER $$;
+CREATE OR REPLACE FUNCTION f1() RETURN INET6 AS
+BEGIN
+ RETURN 'ffff::ffff';
+END;
+$$
+DELIMITER ;$$
+SELECT f1();
+DROP FUNCTION f1;
+
+
+SET sql_mode=ORACLE;
+DELIMITER $$;
+CREATE OR REPLACE FUNCTION f1(a INET6) RETURN INT AS
+BEGIN
+ RETURN LENGTH(a);
+END;
+$$
+DELIMITER ;$$
+SELECT f1('0::0');
+DROP FUNCTION f1;
+
+
+--echo #
+--echo # End of 10.5 tests
+--echo #
diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_partition.result b/plugin/type_inet/mysql-test/type_inet/type_inet6_partition.result
new file mode 100644
index 00000000..48f10a39
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_partition.result
@@ -0,0 +1,29 @@
+#
+# MDEV-20831 Table partitioned by LIST/RANGE COLUMNS(inet6) can be created, but not inserted into
+#
+SET NAMES utf8;
+CREATE TABLE t1 (a INET6)
+PARTITION BY LIST COLUMNS(a)
+(PARTITION p00 VALUES IN (10));
+ERROR HY000: Partition column values of incorrect type
+CREATE TABLE t1 (a INET6)
+PARTITION BY LIST COLUMNS(a)
+(PARTITION p00 VALUES IN (TIME'10:20:30'));
+ERROR HY000: Partition column values of incorrect type
+CREATE TABLE t1 (a INET6)
+PARTITION BY LIST COLUMNS(a)
+(PARTITION p00 VALUES IN ('€'));
+ERROR 22007: Incorrect inet6 value: '€'
+CREATE TABLE t1 (a INET6)
+PARTITION BY LIST COLUMNS(a)
+(PARTITION p00 VALUES IN ('::'),
+PARTITION pFF VALUES IN (0xFFFF000000000000000000000000FFFF));
+INSERT INTO t1 VALUES ('::');
+INSERT INTO t1 VALUES ('ffff::ffff');
+SELECT * FROM t1 PARTITION (p00);
+a
+::
+SELECT * FROM t1 PARTITION (pFF);
+a
+ffff::ffff
+DROP TABLE t1;
diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_partition.test b/plugin/type_inet/mysql-test/type_inet/type_inet6_partition.test
new file mode 100644
index 00000000..76ab2478
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_partition.test
@@ -0,0 +1,32 @@
+--source include/have_partition.inc
+
+--echo #
+--echo # MDEV-20831 Table partitioned by LIST/RANGE COLUMNS(inet6) can be created, but not inserted into
+--echo #
+
+SET NAMES utf8;
+
+--error ER_WRONG_TYPE_COLUMN_VALUE_ERROR
+CREATE TABLE t1 (a INET6)
+ PARTITION BY LIST COLUMNS(a)
+ (PARTITION p00 VALUES IN (10));
+
+--error ER_WRONG_TYPE_COLUMN_VALUE_ERROR
+CREATE TABLE t1 (a INET6)
+ PARTITION BY LIST COLUMNS(a)
+ (PARTITION p00 VALUES IN (TIME'10:20:30'));
+
+--error ER_TRUNCATED_WRONG_VALUE
+CREATE TABLE t1 (a INET6)
+ PARTITION BY LIST COLUMNS(a)
+ (PARTITION p00 VALUES IN ('€'));
+
+CREATE TABLE t1 (a INET6)
+ PARTITION BY LIST COLUMNS(a)
+ (PARTITION p00 VALUES IN ('::'),
+ PARTITION pFF VALUES IN (0xFFFF000000000000000000000000FFFF));
+INSERT INTO t1 VALUES ('::');
+INSERT INTO t1 VALUES ('ffff::ffff');
+SELECT * FROM t1 PARTITION (p00);
+SELECT * FROM t1 PARTITION (pFF);
+DROP TABLE t1;
diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_plugin.result b/plugin/type_inet/mysql-test/type_inet/type_inet6_plugin.result
new file mode 100644
index 00000000..200ab307
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_plugin.result
@@ -0,0 +1,31 @@
+#
+# Start of 10.5 tests
+#
+#
+# MDEV-274 The data type for IPv6/IPv4 addresses in MariaDB
+#
+SELECT
+PLUGIN_NAME,
+PLUGIN_VERSION,
+PLUGIN_STATUS,
+PLUGIN_TYPE,
+PLUGIN_AUTHOR,
+PLUGIN_DESCRIPTION,
+PLUGIN_LICENSE,
+PLUGIN_MATURITY,
+PLUGIN_AUTH_VERSION
+FROM INFORMATION_SCHEMA.PLUGINS
+WHERE PLUGIN_TYPE='DATA TYPE'
+ AND PLUGIN_NAME='inet6';
+PLUGIN_NAME inet6
+PLUGIN_VERSION 1.0
+PLUGIN_STATUS ACTIVE
+PLUGIN_TYPE DATA TYPE
+PLUGIN_AUTHOR MariaDB Corporation
+PLUGIN_DESCRIPTION Data type INET6
+PLUGIN_LICENSE GPL
+PLUGIN_MATURITY Stable
+PLUGIN_AUTH_VERSION 1.0
+#
+# End of 10.5 tests
+#
diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_plugin.test b/plugin/type_inet/mysql-test/type_inet/type_inet6_plugin.test
new file mode 100644
index 00000000..ccc22b16
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_plugin.test
@@ -0,0 +1,27 @@
+--echo #
+--echo # Start of 10.5 tests
+--echo #
+
+--echo #
+--echo # MDEV-274 The data type for IPv6/IPv4 addresses in MariaDB
+--echo #
+
+--vertical_results
+SELECT
+ PLUGIN_NAME,
+ PLUGIN_VERSION,
+ PLUGIN_STATUS,
+ PLUGIN_TYPE,
+ PLUGIN_AUTHOR,
+ PLUGIN_DESCRIPTION,
+ PLUGIN_LICENSE,
+ PLUGIN_MATURITY,
+ PLUGIN_AUTH_VERSION
+FROM INFORMATION_SCHEMA.PLUGINS
+ WHERE PLUGIN_TYPE='DATA TYPE'
+ AND PLUGIN_NAME='inet6';
+--horizontal_results
+
+--echo #
+--echo # End of 10.5 tests
+--echo #
diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_stat_tables.result b/plugin/type_inet/mysql-test/type_inet/type_inet6_stat_tables.result
new file mode 100644
index 00000000..1cbedad1
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_stat_tables.result
@@ -0,0 +1,31 @@
+#
+# Start of 10.5 tests
+#
+#
+# MDEV-20800 Server crashes in Field_inet6::store_warning upon updating table statistics
+#
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('1::1'),('2::2');
+ANALYZE TABLE t1 PERSISTENT FOR ALL;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+INSERT INTO t1 VALUES ('3::3');
+DROP TABLE t1;
+#
+# MDEV-22509: Server crashes in Field_inet6::store_inet6_null_with_warn / Field::maybe_null
+#
+CREATE TABLE t1 (a INT, b INET6 NOT NULL);
+INSERT INTO t1 VALUES (1,'::'),(2,'::');
+ANALYZE TABLE t1 PERSISTENT FOR ALL;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+SELECT t1.a from t1;
+a
+1
+2
+DROP TABLE t1;
+#
+# End of 10.5 tests
+#
diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_stat_tables.test b/plugin/type_inet/mysql-test/type_inet/type_inet6_stat_tables.test
new file mode 100644
index 00000000..063581b1
--- /dev/null
+++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_stat_tables.test
@@ -0,0 +1,29 @@
+--source include/have_stat_tables.inc
+
+--echo #
+--echo # Start of 10.5 tests
+--echo #
+
+--echo #
+--echo # MDEV-20800 Server crashes in Field_inet6::store_warning upon updating table statistics
+--echo #
+
+CREATE TABLE t1 (a INET6);
+INSERT INTO t1 VALUES ('1::1'),('2::2');
+ANALYZE TABLE t1 PERSISTENT FOR ALL;
+INSERT INTO t1 VALUES ('3::3');
+DROP TABLE t1;
+
+--echo #
+--echo # MDEV-22509: Server crashes in Field_inet6::store_inet6_null_with_warn / Field::maybe_null
+--echo #
+
+CREATE TABLE t1 (a INT, b INET6 NOT NULL);
+INSERT INTO t1 VALUES (1,'::'),(2,'::');
+ANALYZE TABLE t1 PERSISTENT FOR ALL;
+SELECT t1.a from t1;
+DROP TABLE t1;
+
+--echo #
+--echo # End of 10.5 tests
+--echo #
diff --git a/plugin/type_inet/plugin.cc b/plugin/type_inet/plugin.cc
new file mode 100644
index 00000000..77804c82
--- /dev/null
+++ b/plugin/type_inet/plugin.cc
@@ -0,0 +1,311 @@
+/* Copyright (c) 2019 MariaDB Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#define MYSQL_SERVER
+#include "mariadb.h"
+#include "sql_class.h"
+#include "sql_type_inet.h"
+#include "item_inetfunc.h"
+#include <mysql/plugin_data_type.h>
+#include <mysql/plugin_function.h>
+
+
+Type_handler_inet6 type_handler_inet6;
+
+
+static struct st_mariadb_data_type plugin_descriptor_type_inet6=
+{
+ MariaDB_DATA_TYPE_INTERFACE_VERSION,
+ &type_handler_inet6
+};
+
+
+/*************************************************************************/
+
+class Create_func_inet_ntoa : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_inet_ntoa(thd, arg1);
+ }
+ static Create_func_inet_ntoa s_singleton;
+protected:
+ Create_func_inet_ntoa() {}
+ virtual ~Create_func_inet_ntoa() {}
+};
+
+
+class Create_func_inet_aton : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_inet_aton(thd, arg1);
+ }
+ static Create_func_inet_aton s_singleton;
+protected:
+ Create_func_inet_aton() {}
+ virtual ~Create_func_inet_aton() {}
+};
+
+
+class Create_func_inet6_aton : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_inet6_aton(thd, arg1);
+ }
+ static Create_func_inet6_aton s_singleton;
+protected:
+ Create_func_inet6_aton() {}
+ virtual ~Create_func_inet6_aton() {}
+};
+
+
+class Create_func_inet6_ntoa : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_inet6_ntoa(thd, arg1);
+ }
+ static Create_func_inet6_ntoa s_singleton;
+protected:
+ Create_func_inet6_ntoa() {}
+ virtual ~Create_func_inet6_ntoa() {}
+};
+
+
+class Create_func_is_ipv4 : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_is_ipv4(thd, arg1);
+ }
+ static Create_func_is_ipv4 s_singleton;
+protected:
+ Create_func_is_ipv4() {}
+ virtual ~Create_func_is_ipv4() {}
+};
+
+
+class Create_func_is_ipv6 : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_is_ipv6(thd, arg1);
+ }
+ static Create_func_is_ipv6 s_singleton;
+protected:
+ Create_func_is_ipv6() {}
+ virtual ~Create_func_is_ipv6() {}
+};
+
+
+class Create_func_is_ipv4_compat : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_is_ipv4_compat(thd, arg1);
+ }
+ static Create_func_is_ipv4_compat s_singleton;
+protected:
+ Create_func_is_ipv4_compat() {}
+ virtual ~Create_func_is_ipv4_compat() {}
+};
+
+
+class Create_func_is_ipv4_mapped : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_is_ipv4_mapped(thd, arg1);
+ }
+ static Create_func_is_ipv4_mapped s_singleton;
+protected:
+ Create_func_is_ipv4_mapped() {}
+ virtual ~Create_func_is_ipv4_mapped() {}
+};
+
+
+Create_func_inet_ntoa Create_func_inet_ntoa::s_singleton;
+Create_func_inet6_aton Create_func_inet6_aton::s_singleton;
+Create_func_inet6_ntoa Create_func_inet6_ntoa::s_singleton;
+Create_func_inet_aton Create_func_inet_aton::s_singleton;
+Create_func_is_ipv4 Create_func_is_ipv4::s_singleton;
+Create_func_is_ipv6 Create_func_is_ipv6::s_singleton;
+Create_func_is_ipv4_compat Create_func_is_ipv4_compat::s_singleton;
+Create_func_is_ipv4_mapped Create_func_is_ipv4_mapped::s_singleton;
+
+
+#define BUILDER(F) & F::s_singleton
+
+
+static Plugin_function
+ plugin_descriptor_function_inet_aton(BUILDER(Create_func_inet_aton)),
+ plugin_descriptor_function_inet_ntoa(BUILDER(Create_func_inet_ntoa)),
+ plugin_descriptor_function_inet6_aton(BUILDER(Create_func_inet6_aton)),
+ plugin_descriptor_function_inet6_ntoa(BUILDER(Create_func_inet6_ntoa)),
+ plugin_descriptor_function_is_ipv4(BUILDER(Create_func_is_ipv4)),
+ plugin_descriptor_function_is_ipv6(BUILDER(Create_func_is_ipv6)),
+ plugin_descriptor_function_is_ipv4_compat(BUILDER(Create_func_is_ipv4_compat)),
+ plugin_descriptor_function_is_ipv4_mapped(BUILDER(Create_func_is_ipv4_mapped));
+
+
+/*************************************************************************/
+
+maria_declare_plugin(type_inet)
+{
+ MariaDB_DATA_TYPE_PLUGIN, // the plugin type (see include/mysql/plugin.h)
+ &plugin_descriptor_type_inet6,// pointer to type-specific plugin descriptor
+ "inet6", // plugin name
+ "MariaDB Corporation", // plugin author
+ "Data type INET6", // the plugin description
+ PLUGIN_LICENSE_GPL, // the plugin license (see include/mysql/plugin.h)
+ 0, // Pointer to plugin initialization function
+ 0, // Pointer to plugin deinitialization function
+ 0x0100, // Numeric version 0xAABB means AA.BB version
+ NULL, // Status variables
+ NULL, // System variables
+ "1.0", // String version representation
+ MariaDB_PLUGIN_MATURITY_STABLE// Maturity(see include/mysql/plugin.h)*/
+},
+{
+ MariaDB_FUNCTION_PLUGIN, // the plugin type (see include/mysql/plugin.h)
+ &plugin_descriptor_function_inet_aton, // pointer to type-specific plugin descriptor
+ "inet_aton", // plugin name
+ "MariaDB Corporation", // plugin author
+ "Function INET_ATON()", // the plugin description
+ PLUGIN_LICENSE_GPL, // the plugin license (see include/mysql/plugin.h)
+ 0, // Pointer to plugin initialization function
+ 0, // Pointer to plugin deinitialization function
+ 0x0100, // Numeric version 0xAABB means AA.BB version
+ NULL, // Status variables
+ NULL, // System variables
+ "1.0", // String version representation
+ MariaDB_PLUGIN_MATURITY_STABLE// Maturity(see include/mysql/plugin.h)*/
+},
+{
+ MariaDB_FUNCTION_PLUGIN, // the plugin type (see include/mysql/plugin.h)
+ &plugin_descriptor_function_inet_ntoa, // pointer to type-specific plugin descriptor
+ "inet_ntoa", // plugin name
+ "MariaDB Corporation", // plugin author
+ "Function INET_NTOA()", // the plugin description
+ PLUGIN_LICENSE_GPL, // the plugin license (see include/mysql/plugin.h)
+ 0, // Pointer to plugin initialization function
+ 0, // Pointer to plugin deinitialization function
+ 0x0100, // Numeric version 0xAABB means AA.BB version
+ NULL, // Status variables
+ NULL, // System variables
+ "1.0", // String version representation
+ MariaDB_PLUGIN_MATURITY_STABLE// Maturity(see include/mysql/plugin.h)*/
+},
+{
+ MariaDB_FUNCTION_PLUGIN, // the plugin type (see include/mysql/plugin.h)
+ &plugin_descriptor_function_inet6_aton, // pointer to type-specific plugin descriptor
+ "inet6_aton", // plugin name
+ "MariaDB Corporation", // plugin author
+ "Function INET6_ATON()", // the plugin description
+ PLUGIN_LICENSE_GPL, // the plugin license (see include/mysql/plugin.h)
+ 0, // Pointer to plugin initialization function
+ 0, // Pointer to plugin deinitialization function
+ 0x0100, // Numeric version 0xAABB means AA.BB version
+ NULL, // Status variables
+ NULL, // System variables
+ "1.0", // String version representation
+ MariaDB_PLUGIN_MATURITY_STABLE// Maturity(see include/mysql/plugin.h)*/
+},
+{
+ MariaDB_FUNCTION_PLUGIN, // the plugin type (see include/mysql/plugin.h)
+ &plugin_descriptor_function_inet6_ntoa, // pointer to type-specific plugin descriptor
+ "inet6_ntoa", // plugin name
+ "MariaDB Corporation", // plugin author
+ "Function INET6_NTOA()", // the plugin description
+ PLUGIN_LICENSE_GPL, // the plugin license (see include/mysql/plugin.h)
+ 0, // Pointer to plugin initialization function
+ 0, // Pointer to plugin deinitialization function
+ 0x0100, // Numeric version 0xAABB means AA.BB version
+ NULL, // Status variables
+ NULL, // System variables
+ "1.0", // String version representation
+ MariaDB_PLUGIN_MATURITY_STABLE// Maturity(see include/mysql/plugin.h)*/
+},
+{
+ MariaDB_FUNCTION_PLUGIN, // the plugin type (see include/mysql/plugin.h)
+ &plugin_descriptor_function_is_ipv4, // pointer to type-specific plugin descriptor
+ "is_ipv4", // plugin name
+ "MariaDB Corporation", // plugin author
+ "Function IS_IPV4()", // the plugin description
+ PLUGIN_LICENSE_GPL, // the plugin license (see include/mysql/plugin.h)
+ 0, // Pointer to plugin initialization function
+ 0, // Pointer to plugin deinitialization function
+ 0x0100, // Numeric version 0xAABB means AA.BB version
+ NULL, // Status variables
+ NULL, // System variables
+ "1.0", // String version representation
+ MariaDB_PLUGIN_MATURITY_STABLE// Maturity(see include/mysql/plugin.h)*/
+},
+{
+ MariaDB_FUNCTION_PLUGIN, // the plugin type (see include/mysql/plugin.h)
+ &plugin_descriptor_function_is_ipv6, // pointer to type-specific plugin descriptor
+ "is_ipv6", // plugin name
+ "MariaDB Corporation", // plugin author
+ "Function IS_IPV6()", // the plugin description
+ PLUGIN_LICENSE_GPL, // the plugin license (see include/mysql/plugin.h)
+ 0, // Pointer to plugin initialization function
+ 0, // Pointer to plugin deinitialization function
+ 0x0100, // Numeric version 0xAABB means AA.BB version
+ NULL, // Status variables
+ NULL, // System variables
+ "1.0", // String version representation
+ MariaDB_PLUGIN_MATURITY_STABLE// Maturity(see include/mysql/plugin.h)*/
+},
+{
+ MariaDB_FUNCTION_PLUGIN, // the plugin type (see include/mysql/plugin.h)
+ &plugin_descriptor_function_is_ipv4_compat, // pointer to type-specific plugin descriptor
+ "is_ipv4_compat", // plugin name
+ "MariaDB Corporation", // plugin author
+ "Function IS_IPV4_COMPAT()", // the plugin description
+ PLUGIN_LICENSE_GPL, // the plugin license (see include/mysql/plugin.h)
+ 0, // Pointer to plugin initialization function
+ 0, // Pointer to plugin deinitialization function
+ 0x0100, // Numeric version 0xAABB means AA.BB version
+ NULL, // Status variables
+ NULL, // System variables
+ "1.0", // String version representation
+ MariaDB_PLUGIN_MATURITY_STABLE// Maturity(see include/mysql/plugin.h)*/
+},
+{
+ MariaDB_FUNCTION_PLUGIN, // the plugin type (see include/mysql/plugin.h)
+ &plugin_descriptor_function_is_ipv4_mapped, // pointer to type-specific plugin descriptor
+ "is_ipv4_mapped", // plugin name
+ "MariaDB Corporation", // plugin author
+ "Function IS_IPV4_MAPPED()",// the plugin description
+ PLUGIN_LICENSE_GPL, // the plugin license (see include/mysql/plugin.h)
+ 0, // Pointer to plugin initialization function
+ 0, // Pointer to plugin deinitialization function
+ 0x0100, // Numeric version 0xAABB means AA.BB version
+ NULL, // Status variables
+ NULL, // System variables
+ "1.0", // String version representation
+ MariaDB_PLUGIN_MATURITY_STABLE// Maturity(see include/mysql/plugin.h)*/
+}
+maria_declare_plugin_end;
diff --git a/plugin/type_inet/sql_type_inet.cc b/plugin/type_inet/sql_type_inet.cc
new file mode 100644
index 00000000..14d854be
--- /dev/null
+++ b/plugin/type_inet/sql_type_inet.cc
@@ -0,0 +1,1642 @@
+/* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2014 MariaDB Foundation
+ Copyright (c) 2019 MariaDB Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#define MYSQL_SERVER
+#include "mariadb.h"
+#include "my_net.h"
+#include "sql_class.h" // THD, SORT_FIELD_ATTR
+#include "opt_range.h" // SEL_ARG
+#include "sql_type_inet.h"
+
+///////////////////////////////////////////////////////////////////////////
+
+static const char HEX_DIGITS[]= "0123456789abcdef";
+
+
+///////////////////////////////////////////////////////////////////////////
+
+/**
+ Tries to convert given string to binary IPv4-address representation.
+ This is a portable alternative to inet_pton(AF_INET).
+
+ @param str String to convert.
+ @param str_length String length.
+
+ @return Completion status.
+ @retval true - error, the given string does not represent an IPv4-address.
+ @retval false - ok, the string has been converted sucessfully.
+
+ @note The problem with inet_pton() is that it treats leading zeros in
+ IPv4-part differently on different platforms.
+*/
+
+bool Inet4::ascii_to_ipv4(const char *str, size_t str_length)
+{
+ if (str_length < 7)
+ {
+ DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): "
+ "invalid IPv4 address: too short.",
+ (int) str_length, str));
+ return true;
+ }
+
+ if (str_length > IN_ADDR_MAX_CHAR_LENGTH)
+ {
+ DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): "
+ "invalid IPv4 address: too long.",
+ (int) str_length, str));
+ return true;
+ }
+
+ unsigned char *ipv4_bytes= (unsigned char *) &m_buffer;
+ const char *str_end= str + str_length;
+ const char *p= str;
+ int byte_value= 0;
+ int chars_in_group= 0;
+ int dot_count= 0;
+ char c= 0;
+
+ while (p < str_end && *p)
+ {
+ c= *p++;
+
+ if (my_isdigit(&my_charset_latin1, c))
+ {
+ ++chars_in_group;
+
+ if (chars_in_group > 3)
+ {
+ DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): invalid IPv4 address: "
+ "too many characters in a group.",
+ (int) str_length, str));
+ return true;
+ }
+
+ byte_value= byte_value * 10 + (c - '0');
+
+ if (byte_value > 255)
+ {
+ DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): invalid IPv4 address: "
+ "invalid byte value.",
+ (int) str_length, str));
+ return true;
+ }
+ }
+ else if (c == '.')
+ {
+ if (chars_in_group == 0)
+ {
+ DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): invalid IPv4 address: "
+ "too few characters in a group.",
+ (int) str_length, str));
+ return true;
+ }
+
+ ipv4_bytes[dot_count]= (unsigned char) byte_value;
+
+ ++dot_count;
+ byte_value= 0;
+ chars_in_group= 0;
+
+ if (dot_count > 3)
+ {
+ DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): invalid IPv4 address: "
+ "too many dots.", (int) str_length, str));
+ return true;
+ }
+ }
+ else
+ {
+ DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): invalid IPv4 address: "
+ "invalid character at pos %d.",
+ (int) str_length, str, (int) (p - str)));
+ return true;
+ }
+ }
+
+ if (c == '.')
+ {
+ DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): invalid IPv4 address: "
+ "ending at '.'.", (int) str_length, str));
+ return true;
+ }
+
+ if (dot_count != 3)
+ {
+ DBUG_PRINT("error", ("ascii_to_ipv4(%.*s): invalid IPv4 address: "
+ "too few groups.",
+ (int) str_length, str));
+ return true;
+ }
+
+ ipv4_bytes[3]= (unsigned char) byte_value;
+
+ DBUG_PRINT("info", ("ascii_to_ipv4(%.*s): valid IPv4 address: %d.%d.%d.%d",
+ (int) str_length, str,
+ ipv4_bytes[0], ipv4_bytes[1],
+ ipv4_bytes[2], ipv4_bytes[3]));
+ return false;
+}
+
+
+/**
+ Tries to convert given string to binary IPv6-address representation.
+ This is a portable alternative to inet_pton(AF_INET6).
+
+ @param str String to convert.
+ @param str_length String length.
+
+ @return Completion status.
+ @retval true - error, the given string does not represent an IPv6-address.
+ @retval false - ok, the string has been converted sucessfully.
+
+ @note The problem with inet_pton() is that it treats leading zeros in
+ IPv4-part differently on different platforms.
+*/
+
+bool Inet6::ascii_to_ipv6(const char *str, size_t str_length)
+{
+ if (str_length < 2)
+ {
+ DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: too short.",
+ (int) str_length, str));
+ return true;
+ }
+
+ if (str_length > IN6_ADDR_MAX_CHAR_LENGTH)
+ {
+ DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: too long.",
+ (int) str_length, str));
+ return true;
+ }
+
+ memset(m_buffer, 0, sizeof(m_buffer));
+
+ const char *p= str;
+
+ if (*p == ':')
+ {
+ ++p;
+
+ if (*p != ':')
+ {
+ DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
+ "can not start with ':x'.", (int) str_length, str));
+ return true;
+ }
+ }
+
+ const char *str_end= str + str_length;
+ char *ipv6_bytes_end= m_buffer + sizeof(m_buffer);
+ char *dst= m_buffer;
+ char *gap_ptr= NULL;
+ const char *group_start_ptr= p;
+ int chars_in_group= 0;
+ int group_value= 0;
+
+ while (p < str_end && *p)
+ {
+ char c= *p++;
+
+ if (c == ':')
+ {
+ group_start_ptr= p;
+
+ if (!chars_in_group)
+ {
+ if (gap_ptr)
+ {
+ DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
+ "too many gaps(::).", (int) str_length, str));
+ return true;
+ }
+
+ gap_ptr= dst;
+ continue;
+ }
+
+ if (!*p || p >= str_end)
+ {
+ DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
+ "ending at ':'.", (int) str_length, str));
+ return true;
+ }
+
+ if (dst + 2 > ipv6_bytes_end)
+ {
+ DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
+ "too many groups (1).", (int) str_length, str));
+ return true;
+ }
+
+ dst[0]= (unsigned char) (group_value >> 8) & 0xff;
+ dst[1]= (unsigned char) group_value & 0xff;
+ dst += 2;
+
+ chars_in_group= 0;
+ group_value= 0;
+ }
+ else if (c == '.')
+ {
+ if (dst + IN_ADDR_SIZE > ipv6_bytes_end)
+ {
+ DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
+ "unexpected IPv4-part.", (int) str_length, str));
+ return true;
+ }
+
+ Inet4_null tmp(group_start_ptr, (size_t) (str_end - group_start_ptr),
+ &my_charset_latin1);
+ if (tmp.is_null())
+ {
+ DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
+ "invalid IPv4-part.", (int) str_length, str));
+ return true;
+ }
+
+ tmp.to_binary(dst, IN_ADDR_SIZE);
+ dst += IN_ADDR_SIZE;
+ chars_in_group= 0;
+
+ break;
+ }
+ else
+ {
+ const char *hdp= strchr(HEX_DIGITS, my_tolower(&my_charset_latin1, c));
+
+ if (!hdp)
+ {
+ DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
+ "invalid character at pos %d.",
+ (int) str_length, str, (int) (p - str)));
+ return true;
+ }
+
+ if (chars_in_group >= 4)
+ {
+ DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
+ "too many digits in group.",
+ (int) str_length, str));
+ return true;
+ }
+
+ group_value <<= 4;
+ group_value |= hdp - HEX_DIGITS;
+
+ DBUG_ASSERT(group_value <= 0xffff);
+
+ ++chars_in_group;
+ }
+ }
+
+ if (chars_in_group > 0)
+ {
+ if (dst + 2 > ipv6_bytes_end)
+ {
+ DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
+ "too many groups (2).", (int) str_length, str));
+ return true;
+ }
+
+ dst[0]= (unsigned char) (group_value >> 8) & 0xff;
+ dst[1]= (unsigned char) group_value & 0xff;
+ dst += 2;
+ }
+
+ if (gap_ptr)
+ {
+ if (dst == ipv6_bytes_end)
+ {
+ DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
+ "no room for a gap (::).", (int) str_length, str));
+ return true;
+ }
+
+ int bytes_to_move= (int)(dst - gap_ptr);
+
+ for (int i= 1; i <= bytes_to_move; ++i)
+ {
+ ipv6_bytes_end[-i]= gap_ptr[bytes_to_move - i];
+ gap_ptr[bytes_to_move - i]= 0;
+ }
+
+ dst= ipv6_bytes_end;
+ }
+
+ if (dst < ipv6_bytes_end)
+ {
+ DBUG_PRINT("error", ("ascii_to_ipv6(%.*s): invalid IPv6 address: "
+ "too few groups.", (int) str_length, str));
+ return true;
+ }
+
+ return false;
+}
+
+
+/**
+ Converts IPv4-binary-address to a string. This function is a portable
+ alternative to inet_ntop(AF_INET).
+
+ @param[in] ipv4 IPv4-address data (byte array)
+ @param[out] dst A buffer to store string representation of IPv4-address.
+ @param[in] dstsize Number of bytes avaiable in "dst"
+
+ @note The problem with inet_ntop() is that it is available starting from
+ Windows Vista, but the minimum supported version is Windows 2000.
+*/
+
+size_t Inet4::to_string(char *dst, size_t dstsize) const
+{
+ return (size_t) my_snprintf(dst, dstsize, "%d.%d.%d.%d",
+ (uchar) m_buffer[0], (uchar) m_buffer[1],
+ (uchar) m_buffer[2], (uchar) m_buffer[3]);
+}
+
+
+/**
+ Converts IPv6-binary-address to a string. This function is a portable
+ alternative to inet_ntop(AF_INET6).
+
+ @param[in] ipv6 IPv6-address data (byte array)
+ @param[out] dst A buffer to store string representation of IPv6-address.
+ It must be at least of INET6_ADDRSTRLEN.
+ @param[in] dstsize Number of bytes available dst.
+
+ @note The problem with inet_ntop() is that it is available starting from
+ Windows Vista, but out the minimum supported version is Windows 2000.
+*/
+
+size_t Inet6::to_string(char *dst, size_t dstsize) const
+{
+ struct Region
+ {
+ int pos;
+ int length;
+ };
+
+ const char *ipv6= m_buffer;
+ char *dstend= dst + dstsize;
+ const unsigned char *ipv6_bytes= (const unsigned char *) ipv6;
+
+ // 1. Translate IPv6-address bytes to words.
+ // We can't just cast to short, because it's not guaranteed
+ // that sizeof (short) == 2. So, we have to make a copy.
+
+ uint16 ipv6_words[IN6_ADDR_NUM_WORDS];
+
+ DBUG_ASSERT(dstsize > 0); // Need a space at least for the trailing '\0'
+ for (size_t i= 0; i < IN6_ADDR_NUM_WORDS; ++i)
+ ipv6_words[i]= (ipv6_bytes[2 * i] << 8) + ipv6_bytes[2 * i + 1];
+
+ // 2. Find "the gap" -- longest sequence of zeros in IPv6-address.
+
+ Region gap= { -1, -1 };
+
+ {
+ Region rg= { -1, -1 };
+
+ for (size_t i= 0; i < IN6_ADDR_NUM_WORDS; ++i)
+ {
+ if (ipv6_words[i] != 0)
+ {
+ if (rg.pos >= 0)
+ {
+ if (rg.length > gap.length)
+ gap= rg;
+
+ rg.pos= -1;
+ rg.length= -1;
+ }
+ }
+ else
+ {
+ if (rg.pos >= 0)
+ {
+ ++rg.length;
+ }
+ else
+ {
+ rg.pos= (int) i;
+ rg.length= 1;
+ }
+ }
+ }
+
+ if (rg.pos >= 0)
+ {
+ if (rg.length > gap.length)
+ gap= rg;
+ }
+ }
+
+ // 3. Convert binary data to string.
+
+ char *p= dst;
+
+ for (int i= 0; i < (int) IN6_ADDR_NUM_WORDS; ++i)
+ {
+ DBUG_ASSERT(dstend >= p);
+ size_t dstsize_available= dstend - p;
+ if (dstsize_available < 5)
+ break;
+ if (i == gap.pos)
+ {
+ // We're at the gap position. We should put trailing ':' and jump to
+ // the end of the gap.
+
+ if (i == 0)
+ {
+ // The gap starts from the beginning of the data -- leading ':'
+ // should be put additionally.
+
+ *p= ':';
+ ++p;
+ }
+
+ *p= ':';
+ ++p;
+
+ i += gap.length - 1;
+ }
+ else if (i == 6 && gap.pos == 0 &&
+ (gap.length == 6 || // IPv4-compatible
+ (gap.length == 5 && ipv6_words[5] == 0xffff) // IPv4-mapped
+ ))
+ {
+ // The data represents either IPv4-compatible or IPv4-mapped address.
+ // The IPv6-part (zeros or zeros + ffff) has been already put into
+ // the string (dst). Now it's time to dump IPv4-part.
+
+ return (size_t) (p - dst) +
+ Inet4_null((const char *) (ipv6_bytes + 12), 4).
+ to_string(p, dstsize_available);
+ }
+ else
+ {
+ // Usual IPv6-address-field. Print it out using lower-case
+ // hex-letters without leading zeros (recommended IPv6-format).
+ //
+ // If it is not the last field, append closing ':'.
+
+ p += sprintf(p, "%x", ipv6_words[i]);
+
+ if (i + 1 != IN6_ADDR_NUM_WORDS)
+ {
+ *p= ':';
+ ++p;
+ }
+ }
+ }
+
+ *p= 0;
+ return (size_t) (p - dst);
+}
+
+
+bool Inet6::fix_fields_maybe_null_on_conversion_to_inet6(Item *item)
+{
+ if (item->maybe_null)
+ return true;
+ if (item->type_handler() == &type_handler_inet6)
+ return false;
+ if (!item->const_item() || item->is_expensive())
+ return true;
+ return Inet6_null(item, false).is_null();
+}
+
+
+bool Inet6::make_from_item(Item *item, bool warn)
+{
+ if (item->type_handler() == &type_handler_inet6)
+ {
+ Native tmp(m_buffer, sizeof(m_buffer));
+ bool rc= item->val_native(current_thd, &tmp);
+ if (rc)
+ return true;
+ DBUG_ASSERT(tmp.length() == sizeof(m_buffer));
+ if (tmp.ptr() != m_buffer)
+ memcpy(m_buffer, tmp.ptr(), sizeof(m_buffer));
+ return false;
+ }
+ StringBufferInet6 tmp;
+ String *str= item->val_str(&tmp);
+ return str ? make_from_character_or_binary_string(str, warn) : true;
+}
+
+
+bool Inet6::make_from_character_or_binary_string(const String *str, bool warn)
+{
+ static Name name= type_handler_inet6.name();
+ if (str->charset() != &my_charset_bin)
+ {
+ bool rc= character_string_to_ipv6(str->ptr(), str->length(),
+ str->charset());
+ if (rc && warn)
+ current_thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN,
+ name.ptr(),
+ ErrConvString(str).ptr());
+ return rc;
+ }
+ if (str->length() != sizeof(m_buffer))
+ {
+ if (warn)
+ current_thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN,
+ name.ptr(),
+ ErrConvString(str).ptr());
+ return true;
+ }
+ DBUG_ASSERT(str->ptr() != m_buffer);
+ memcpy(m_buffer, str->ptr(), sizeof(m_buffer));
+ return false;
+};
+
+
+/********************************************************************/
+
+
+class cmp_item_inet6: public cmp_item_scalar
+{
+ Inet6 m_native;
+public:
+ cmp_item_inet6()
+ :cmp_item_scalar(),
+ m_native(Inet6_zero())
+ { }
+ void store_value(Item *item) override
+ {
+ m_native= Inet6(item, &m_null_value);
+ }
+ int cmp_not_null(const Value *val) override
+ {
+ DBUG_ASSERT(!val->is_null());
+ DBUG_ASSERT(val->is_string());
+ Inet6_null tmp(val->m_string);
+ DBUG_ASSERT(!tmp.is_null());
+ return m_native.cmp(tmp);
+ }
+ int cmp(Item *arg) override
+ {
+ Inet6_null tmp(arg);
+ return m_null_value || tmp.is_null() ? UNKNOWN : m_native.cmp(tmp) != 0;
+ }
+ int compare(cmp_item *ci) override
+ {
+ cmp_item_inet6 *tmp= static_cast<cmp_item_inet6*>(ci);
+ DBUG_ASSERT(!m_null_value);
+ DBUG_ASSERT(!tmp->m_null_value);
+ return m_native.cmp(tmp->m_native);
+ }
+ cmp_item *make_same() override
+ {
+ return new cmp_item_inet6();
+ }
+};
+
+
+class Field_inet6: public Field
+{
+ static void set_min_value(char *ptr)
+ {
+ memset(ptr, 0, Inet6::binary_length());
+ }
+ static void set_max_value(char *ptr)
+ {
+ memset(ptr, 0xFF, Inet6::binary_length());
+ }
+ void store_warning(const ErrConv &str,
+ Sql_condition::enum_warning_level level)
+ {
+ static const Name type_name= type_handler_inet6.name();
+ if (get_thd()->count_cuted_fields <= CHECK_FIELD_EXPRESSION)
+ return;
+ const TABLE_SHARE *s= table->s;
+ get_thd()->push_warning_truncated_value_for_field(level, type_name.ptr(),
+ str.ptr(),
+ s ? s->db.str : nullptr,
+ s ? s->table_name.str
+ : nullptr,
+ field_name.str);
+ }
+ int set_null_with_warn(const ErrConv &str)
+ {
+ store_warning(str, Sql_condition::WARN_LEVEL_WARN);
+ set_null();
+ return 1;
+ }
+ int set_min_value_with_warn(const ErrConv &str)
+ {
+ store_warning(str, Sql_condition::WARN_LEVEL_WARN);
+ set_min_value((char*) ptr);
+ return 1;
+ }
+ int set_max_value_with_warn(const ErrConv &str)
+ {
+ store_warning(str, Sql_condition::WARN_LEVEL_WARN);
+ set_max_value((char*) ptr);
+ return 1;
+ }
+ int store_inet6_null_with_warn(const Inet6_null &inet6,
+ const ErrConvString &err)
+ {
+ DBUG_ASSERT(marked_for_write_or_computed());
+ if (inet6.is_null())
+ return maybe_null() ? set_null_with_warn(err) :
+ set_min_value_with_warn(err);
+ inet6.to_binary((char *) ptr, Inet6::binary_length());
+ return 0;
+ }
+
+public:
+ Field_inet6(const LEX_CSTRING *field_name_arg, const Record_addr &rec)
+ :Field(rec.ptr(), Inet6::max_char_length(),
+ rec.null_ptr(), rec.null_bit(), Field::NONE, field_name_arg)
+ {
+ flags|= BINARY_FLAG | UNSIGNED_FLAG;
+ }
+ const Type_handler *type_handler() const override
+ {
+ return &type_handler_inet6;
+ }
+ uint32 max_display_length() const override { return field_length; }
+ bool str_needs_quotes() const override { return true; }
+ const DTCollation &dtcollation() const override
+ {
+ static DTCollation_numeric c;
+ return c;
+ }
+ CHARSET_INFO *charset(void) const override { return &my_charset_numeric; }
+ const CHARSET_INFO *sort_charset(void) const override { return &my_charset_bin; }
+ /**
+ This makes client-server protocol convert the value according
+ to @@character_set_client.
+ */
+ bool binary() const override { return false; }
+ enum ha_base_keytype key_type() const override { return HA_KEYTYPE_BINARY; }
+
+ bool is_equal(const Column_definition &new_field) const override
+ {
+ return new_field.type_handler() == type_handler();
+ }
+ bool eq_def(const Field *field) const override
+ {
+ return Field::eq_def(field);
+ }
+ double pos_in_interval(Field *min, Field *max) override
+ {
+ return pos_in_interval_val_str(min, max, 0);
+ }
+ int cmp(const uchar *a, const uchar *b) const override
+ { return memcmp(a, b, pack_length()); }
+
+ void sort_string(uchar *to, uint length) override
+ {
+ DBUG_ASSERT(length == pack_length());
+ memcpy(to, ptr, length);
+ }
+ uint32 pack_length() const override
+ {
+ return Inet6::binary_length();
+ }
+ uint pack_length_from_metadata(uint field_metadata) const override
+ {
+ return Inet6::binary_length();
+ }
+
+ void sql_type(String &str) const override
+ {
+ static Name name= type_handler_inet6.name();
+ str.set_ascii(name.ptr(), name.length());
+ }
+
+ void make_send_field(Send_field *to) override
+ {
+ Field::make_send_field(to);
+ to->set_data_type_name(type_handler_inet6.name().lex_cstring());
+ }
+
+ bool validate_value_in_record(THD *thd, const uchar *record) const override
+ {
+ return false;
+ }
+
+ String *val_str(String *val_buffer,
+ String *val_ptr __attribute__((unused))) override
+ {
+ DBUG_ASSERT(marked_for_read());
+ Inet6_null tmp((const char *) ptr, pack_length());
+ return tmp.to_string(val_buffer) ? NULL : val_buffer;
+ }
+
+ my_decimal *val_decimal(my_decimal *to) override
+ {
+ DBUG_ASSERT(marked_for_read());
+ my_decimal_set_zero(to);
+ return to;
+ }
+
+ longlong val_int() override
+ {
+ DBUG_ASSERT(marked_for_read());
+ return 0;
+ }
+
+ double val_real() override
+ {
+ DBUG_ASSERT(marked_for_read());
+ return 0;
+ }
+
+ bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate) override
+ {
+ DBUG_ASSERT(marked_for_read());
+ set_zero_time(ltime, MYSQL_TIMESTAMP_TIME);
+ return false;
+ }
+
+ bool val_bool(void) override
+ {
+ DBUG_ASSERT(marked_for_read());
+ return !Inet6::only_zero_bytes((const char *) ptr, Inet6::binary_length());
+ }
+
+ int store_native(const Native &value) override
+ {
+ DBUG_ASSERT(marked_for_write_or_computed());
+ DBUG_ASSERT(value.length() == Inet6::binary_length());
+ memcpy(ptr, value.ptr(), value.length());
+ return 0;
+ }
+
+ int store(const char *str, size_t length, CHARSET_INFO *cs) override
+ {
+ return cs == &my_charset_bin ? store_binary(str, length) :
+ store_text(str, length, cs);
+ }
+
+ int store_text(const char *str, size_t length, CHARSET_INFO *cs) override
+ {
+ return store_inet6_null_with_warn(Inet6_null(str, length, cs),
+ ErrConvString(str, length, cs));
+ }
+
+ int store_binary(const char *str, size_t length) override
+ {
+ return store_inet6_null_with_warn(Inet6_null(str, length),
+ ErrConvString(str, length,
+ &my_charset_bin));
+ }
+
+ int store_hex_hybrid(const char *str, size_t length) override
+ {
+ return Field_inet6::store_binary(str, length);
+ }
+
+ int store_decimal(const my_decimal *num) override
+ {
+ DBUG_ASSERT(marked_for_write_or_computed());
+ return set_min_value_with_warn(ErrConvDecimal(num));
+ }
+
+ int store(longlong nr, bool unsigned_flag) override
+ {
+ DBUG_ASSERT(marked_for_write_or_computed());
+ return set_min_value_with_warn(
+ ErrConvInteger(Longlong_hybrid(nr, unsigned_flag)));
+ }
+
+ int store(double nr) override
+ {
+ DBUG_ASSERT(marked_for_write_or_computed());
+ return set_min_value_with_warn(ErrConvDouble(nr));
+ }
+
+ int store_time_dec(const MYSQL_TIME *ltime, uint dec) override
+ {
+ DBUG_ASSERT(marked_for_write_or_computed());
+ return set_min_value_with_warn(ErrConvTime(ltime));
+ }
+
+ /*** Field conversion routines ***/
+ int store_field(Field *from) override
+ {
+ // INSERT INTO t1 (inet6_field) SELECT different_field_type FROM t2;
+ return from->save_in_field(this);
+ }
+ int save_in_field(Field *to) override
+ {
+ // INSERT INTO t2 (different_field_type) SELECT inet6_field FROM t1;
+ if (to->charset() == &my_charset_bin &&
+ dynamic_cast<const Type_handler_general_purpose_string*>
+ (to->type_handler()))
+ {
+ NativeBufferInet6 res;
+ val_native(&res);
+ return to->store(res.ptr(), res.length(), &my_charset_bin);
+ }
+ return save_in_field_str(to);
+ }
+ Copy_func *get_copy_func(const Field *from) const override
+ {
+ // ALTER to INET6 from another field
+ return do_field_string;
+ }
+
+ Copy_func *get_copy_func_to(const Field *to) const override
+ {
+ if (type_handler() == to->type_handler())
+ {
+ // ALTER from INET6 to INET6
+ DBUG_ASSERT(pack_length() == to->pack_length());
+ DBUG_ASSERT(charset() == to->charset());
+ DBUG_ASSERT(sort_charset() == to->sort_charset());
+ return Field::do_field_eq;
+ }
+ // ALTER from INET6 to another data type
+ if (to->charset() == &my_charset_bin &&
+ dynamic_cast<const Type_handler_general_purpose_string*>
+ (to->type_handler()))
+ {
+ /*
+ ALTER from INET6 to a binary string type, e.g.:
+ BINARY, TINYBLOB, BLOB, MEDIUMBLOB, LONGBLOB
+ */
+ return do_field_inet6_native_to_binary;
+ }
+ return do_field_string;
+ }
+
+ static void do_field_inet6_native_to_binary(Copy_field *copy)
+ {
+ NativeBufferInet6 res;
+ copy->from_field->val_native(&res);
+ copy->to_field->store(res.ptr(), res.length(), &my_charset_bin);
+ }
+
+ bool memcpy_field_possible(const Field *from) const override
+ {
+ // INSERT INTO t1 (inet6_field) SELECT field2 FROM t2;
+ return type_handler() == from->type_handler();
+ }
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const override
+ {
+ if (type_handler() == source.type_handler() ||
+ (source.type_handler() == &type_handler_string &&
+ source.type_handler()->max_display_length_for_field(source) ==
+ Inet6::binary_length()))
+ return rpl_conv_type_from_same_data_type(source.metadata(), rli, param);
+ return CONV_TYPE_IMPOSSIBLE;
+ }
+
+ /*** Optimizer routines ***/
+ bool test_if_equality_guarantees_uniqueness(const Item *const_item) const override
+ {
+ /*
+ This condition:
+ WHERE inet6_field=const
+ should return a single distinct value only,
+ as comparison is done according to INET6.
+ */
+ return true;
+ }
+ bool can_be_substituted_to_equal_item(const Context &ctx,
+ const Item_equal *item_equal)
+ override
+ {
+ switch (ctx.subst_constraint()) {
+ case ANY_SUBST:
+ return ctx.compare_type_handler() == item_equal->compare_type_handler();
+ case IDENTITY_SUBST:
+ return true;
+ }
+ return false;
+ }
+ Item *get_equal_const_item(THD *thd, const Context &ctx,
+ Item *const_item) override;
+ bool can_optimize_keypart_ref(const Item_bool_func *cond,
+ const Item *item) const override
+ {
+ /*
+ Mixing of two different non-traditional types is currently prevented.
+ This may change in the future. For example, INET4 and INET6
+ data types can be made comparable.
+ */
+ DBUG_ASSERT(item->type_handler()->is_traditional_scalar_type() ||
+ item->type_handler() == type_handler());
+ return true;
+ }
+ /**
+ Test if Field can use range optimizer for a standard comparison operation:
+ <=, <, =, <=>, >, >=
+ Note, this method does not cover spatial operations.
+ */
+ bool can_optimize_range(const Item_bool_func *cond,
+ const Item *item,
+ bool is_eq_func) const override
+ {
+ // See the DBUG_ASSERT comment in can_optimize_keypart_ref()
+ DBUG_ASSERT(item->type_handler()->is_traditional_scalar_type() ||
+ item->type_handler() == type_handler());
+ return true;
+ }
+ SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *prm, KEY_PART *key_part,
+ const Item_bool_func *cond,
+ scalar_comparison_op op, Item *value) override
+ {
+ DBUG_ENTER("Field_inet6::get_mm_leaf");
+ if (!can_optimize_scalar_range(prm, key_part, cond, op, value))
+ DBUG_RETURN(0);
+ int err= value->save_in_field_no_warnings(this, 1);
+ if ((op != SCALAR_CMP_EQUAL && is_real_null()) || err < 0)
+ DBUG_RETURN(&null_element);
+ if (err > 0)
+ {
+ if (op == SCALAR_CMP_EQ || op == SCALAR_CMP_EQUAL)
+ DBUG_RETURN(new (prm->mem_root) SEL_ARG_IMPOSSIBLE(this));
+ DBUG_RETURN(NULL); /* Cannot infer anything */
+ }
+ DBUG_RETURN(stored_field_make_mm_leaf(prm, key_part, op, value));
+ }
+ bool can_optimize_hash_join(const Item_bool_func *cond,
+ const Item *item) const override
+ {
+ return can_optimize_keypart_ref(cond, item);
+ }
+ bool can_optimize_group_min_max(const Item_bool_func *cond,
+ const Item *const_item) const override
+ {
+ return true;
+ }
+
+ uint row_pack_length() const override { return pack_length(); }
+
+ Binlog_type_info binlog_type_info() const override
+ {
+ DBUG_ASSERT(type() == binlog_type());
+ return Binlog_type_info_fixed_string(Field_inet6::binlog_type(),
+ Inet6::binary_length(),
+ &my_charset_bin);
+ }
+
+ uchar *pack(uchar *to, const uchar *from, uint max_length) override
+ {
+ DBUG_PRINT("debug", ("Packing field '%s'", field_name.str));
+ return StringPack(&my_charset_bin, Inet6::binary_length()).
+ pack(to, from, max_length);
+ }
+
+ const uchar *unpack(uchar *to, const uchar *from, const uchar *from_end,
+ uint param_data) override
+ {
+ return StringPack(&my_charset_bin, Inet6::binary_length()).
+ unpack(to, from, from_end, param_data);
+ }
+
+ uint max_packed_col_length(uint max_length) override
+ {
+ return StringPack::max_packed_col_length(max_length);
+ }
+
+ uint packed_col_length(const uchar *data_ptr, uint length) override
+ {
+ return StringPack::packed_col_length(data_ptr, length);
+ }
+
+ /**********/
+ uint size_of() const override { return sizeof(*this); }
+};
+
+
+class Item_typecast_inet6: public Item_func
+{
+public:
+ Item_typecast_inet6(THD *thd, Item *a) :Item_func(thd, a) {}
+
+ const Type_handler *type_handler() const override
+ { return &type_handler_inet6; }
+
+ enum Functype functype() const override { return CHAR_TYPECAST_FUNC; }
+ bool eq(const Item *item, bool binary_cmp) const override
+ {
+ if (this == item)
+ return true;
+ if (item->type() != FUNC_ITEM ||
+ functype() != ((Item_func*)item)->functype())
+ return false;
+ if (type_handler() != item->type_handler())
+ return false;
+ Item_typecast_inet6 *cast= (Item_typecast_inet6*) item;
+ return args[0]->eq(cast->args[0], binary_cmp);
+ }
+ const char *func_name() const override { return "cast_as_inet6"; }
+ void print(String *str, enum_query_type query_type) override
+ {
+ str->append(STRING_WITH_LEN("cast("));
+ args[0]->print(str, query_type);
+ str->append(STRING_WITH_LEN(" as inet6)"));
+ }
+ bool fix_length_and_dec() override
+ {
+ Type_std_attributes::operator=(Type_std_attributes_inet6());
+ if (Inet6::fix_fields_maybe_null_on_conversion_to_inet6(args[0]))
+ maybe_null= true;
+ return false;
+ }
+ String *val_str(String *to) override
+ {
+ Inet6_null tmp(args[0]);
+ return (null_value= tmp.is_null() || tmp.to_string(to)) ? NULL : to;
+ }
+ longlong val_int() override
+ {
+ return 0;
+ }
+ double val_real() override
+ {
+ return 0;
+ }
+ my_decimal *val_decimal(my_decimal *to) override
+ {
+ my_decimal_set_zero(to);
+ return to;
+ }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override
+ {
+ set_zero_time(ltime, MYSQL_TIMESTAMP_TIME);
+ return false;
+ }
+ bool val_native(THD *thd, Native *to) override
+ {
+ Inet6_null tmp(args[0]);
+ return null_value= tmp.is_null() || tmp.to_native(to);
+ }
+ Item *get_copy(THD *thd) override
+ { return get_item_copy<Item_typecast_inet6>(thd, this); }
+};
+
+
+class Item_cache_inet6: public Item_cache
+{
+ NativeBufferInet6 m_value;
+public:
+ Item_cache_inet6(THD *thd)
+ :Item_cache(thd, &type_handler_inet6)
+ { }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_cache_inet6>(thd, this); }
+ bool cache_value()
+ {
+ if (!example)
+ return false;
+ value_cached= true;
+ null_value= example->val_native_with_conversion_result(current_thd,
+ &m_value,
+ type_handler());
+ return true;
+ }
+ String* val_str(String *to)
+ {
+ if (!has_value())
+ return NULL;
+ Inet6_null tmp(m_value.ptr(), m_value.length());
+ return tmp.is_null() || tmp.to_string(to) ? NULL : to;
+ }
+ my_decimal *val_decimal(my_decimal *to)
+ {
+ if (!has_value())
+ return NULL;
+ my_decimal_set_zero(to);
+ return to;
+ }
+ longlong val_int()
+ {
+ if (!has_value())
+ return 0;
+ return 0;
+ }
+ double val_real()
+ {
+ if (!has_value())
+ return 0;
+ return 0;
+ }
+ longlong val_datetime_packed(THD *thd)
+ {
+ DBUG_ASSERT(0);
+ if (!has_value())
+ return 0;
+ return 0;
+ }
+ longlong val_time_packed(THD *thd)
+ {
+ DBUG_ASSERT(0);
+ if (!has_value())
+ return 0;
+ return 0;
+ }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
+ {
+ if (!has_value())
+ return true;
+ set_zero_time(ltime, MYSQL_TIMESTAMP_TIME);
+ return false;
+ }
+ bool val_native(THD *thd, Native *to)
+ {
+ if (!has_value())
+ return true;
+ return to->copy(m_value.ptr(), m_value.length());
+ }
+};
+
+
+class Item_literal_inet6: public Item_literal
+{
+ Inet6 m_value;
+public:
+ Item_literal_inet6(THD *thd)
+ :Item_literal(thd),
+ m_value(Inet6_zero())
+ { }
+ Item_literal_inet6(THD *thd, const Inet6 &value)
+ :Item_literal(thd),
+ m_value(value)
+ { }
+ const Type_handler *type_handler() const override
+ {
+ return &type_handler_inet6;
+ }
+ longlong val_int() override
+ {
+ return 0;
+ }
+ double val_real() override
+ {
+ return 0;
+ }
+ String *val_str(String *to) override
+ {
+ return m_value.to_string(to) ? NULL : to;
+ }
+ my_decimal *val_decimal(my_decimal *to) override
+ {
+ my_decimal_set_zero(to);
+ return to;
+ }
+ bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override
+ {
+ set_zero_time(ltime, MYSQL_TIMESTAMP_TIME);
+ return false;
+ }
+ bool val_native(THD *thd, Native *to) override
+ {
+ return m_value.to_native(to);
+ }
+ void print(String *str, enum_query_type query_type) override
+ {
+ StringBufferInet6 tmp;
+ m_value.to_string(&tmp);
+ str->append("INET6'");
+ str->append(tmp);
+ str->append('\'');
+ }
+ Item *get_copy(THD *thd) override
+ { return get_item_copy<Item_literal_inet6>(thd, this); }
+
+ // Non-overriding methods
+ void set_value(const Inet6 &value)
+ {
+ m_value= value;
+ }
+};
+
+
+class in_inet6 :public in_vector
+{
+ Inet6 m_value;
+ static int cmp_inet6(void *cmp_arg, Inet6 *a, Inet6 *b)
+ {
+ return a->cmp(*b);
+ }
+public:
+ in_inet6(THD *thd, uint elements)
+ :in_vector(thd, elements, sizeof(Inet6), (qsort2_cmp) cmp_inet6, 0),
+ m_value(Inet6_zero())
+ { }
+ const Type_handler *type_handler() const override
+ {
+ return &type_handler_inet6;
+ }
+ void set(uint pos, Item *item) override
+ {
+ Inet6 *buff= &((Inet6 *) base)[pos];
+ Inet6_null value(item);
+ if (value.is_null())
+ *buff= Inet6_zero();
+ else
+ *buff= value;
+ }
+ uchar *get_value(Item *item) override
+ {
+ Inet6_null value(item);
+ if (value.is_null())
+ return 0;
+ m_value= value;
+ return (uchar *) &m_value;
+ }
+ Item* create_item(THD *thd) override
+ {
+ return new (thd->mem_root) Item_literal_inet6(thd);
+ }
+ void value_to_item(uint pos, Item *item) override
+ {
+ const Inet6 &buff= (((Inet6*) base)[pos]);
+ static_cast<Item_literal_inet6*>(item)->set_value(buff);
+ }
+};
+
+
+class Item_char_typecast_func_handler_inet6_to_binary:
+ public Item_handled_func::Handler_str
+{
+public:
+ const Type_handler *return_type_handler(const Item_handled_func *item)
+ const override
+ {
+ if (item->max_length > MAX_FIELD_VARCHARLENGTH)
+ return Type_handler::blob_type_handler(item->max_length);
+ if (item->max_length > 255)
+ return &type_handler_varchar;
+ return &type_handler_string;
+ }
+ bool fix_length_and_dec(Item_handled_func *xitem) const override
+ {
+ return false;
+ }
+ String *val_str(Item_handled_func *item, String *to) const override
+ {
+ DBUG_ASSERT(dynamic_cast<const Item_char_typecast*>(item));
+ return static_cast<Item_char_typecast*>(item)->
+ val_str_binary_from_native(to);
+ }
+};
+
+
+static Item_char_typecast_func_handler_inet6_to_binary
+ item_char_typecast_func_handler_inet6_to_binary;
+
+
+bool Type_handler_inet6::
+ Item_char_typecast_fix_length_and_dec(Item_char_typecast *item) const
+{
+ if (item->cast_charset() == &my_charset_bin)
+ {
+ item->fix_length_and_dec_native_to_binary(Inet6::binary_length());
+ item->set_func_handler(&item_char_typecast_func_handler_inet6_to_binary);
+ return false;
+ }
+ item->fix_length_and_dec_str();
+ return false;
+}
+
+
+bool
+Type_handler_inet6::character_or_binary_string_to_native(THD *thd,
+ const String *str,
+ Native *to) const
+{
+ if (str->charset() == &my_charset_bin)
+ {
+ // Convert from a binary string
+ if (str->length() != Inet6::binary_length() ||
+ to->copy(str->ptr(), str->length()))
+ {
+ thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN,
+ name().ptr(),
+ ErrConvString(str).ptr());
+ return true;
+ }
+ return false;
+ }
+ // Convert from a character string
+ Inet6_null tmp(*str);
+ if (tmp.is_null())
+ thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN,
+ name().ptr(),
+ ErrConvString(str).ptr());
+ return tmp.is_null() || tmp.to_native(to);
+}
+
+
+bool
+Type_handler_inet6::Item_save_in_value(THD *thd,
+ Item *item,
+ st_value *value) const
+{
+ value->m_type= DYN_COL_STRING;
+ String *str= item->val_str(&value->m_string);
+ if (str != &value->m_string && !item->null_value)
+ {
+ // "item" returned a non-NULL value
+ if (Inet6_null(*str).is_null())
+ {
+ /*
+ The value was not-null, but conversion to INET6 failed:
+ SELECT a, DECODE_ORACLE(inet6col, 'garbage', '<NULL>', '::01', '01')
+ FROM t1;
+ */
+ thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN,
+ name().ptr(),
+ ErrConvString(str).ptr());
+ value->m_type= DYN_COL_NULL;
+ return true;
+ }
+ // "item" returned a non-NULL value, and it was a valid INET6
+ value->m_string.set(str->ptr(), str->length(), str->charset());
+ }
+ return check_null(item, value);
+}
+
+
+void Type_handler_inet6::Item_param_setup_conversion(THD *thd,
+ Item_param *param) const
+{
+ param->setup_conversion_string(thd, thd->variables.character_set_client);
+}
+
+
+void Type_handler_inet6::make_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const
+{
+ DBUG_ASSERT(item->type_handler() == this);
+ NativeBufferInet6 tmp;
+ item->val_native_result(current_thd, &tmp);
+ if (item->maybe_null)
+ {
+ if (item->null_value)
+ {
+ memset(to, 0, Inet6::binary_length() + 1);
+ return;
+ }
+ *to++= 1;
+ }
+ DBUG_ASSERT(!item->null_value);
+ DBUG_ASSERT(Inet6::binary_length() == tmp.length());
+ DBUG_ASSERT(Inet6::binary_length() == sort_field->length);
+ memcpy(to, tmp.ptr(), tmp.length());
+}
+
+uint
+Type_handler_inet6::make_packed_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const
+{
+ DBUG_ASSERT(item->type_handler() == this);
+ NativeBufferInet6 tmp;
+ item->val_native_result(current_thd, &tmp);
+ if (item->maybe_null)
+ {
+ if (item->null_value)
+ {
+ *to++=0;
+ return 0;
+ }
+ *to++= 1;
+ }
+ DBUG_ASSERT(!item->null_value);
+ DBUG_ASSERT(Inet6::binary_length() == tmp.length());
+ DBUG_ASSERT(Inet6::binary_length() == sort_field->length);
+ memcpy(to, tmp.ptr(), tmp.length());
+ return tmp.length();
+}
+
+void Type_handler_inet6::sort_length(THD *thd,
+ const Type_std_attributes *item,
+ SORT_FIELD_ATTR *attr) const
+{
+ attr->original_length= attr->length= Inet6::binary_length();
+ attr->suffix_length= 0;
+}
+
+
+cmp_item *Type_handler_inet6::make_cmp_item(THD *thd, CHARSET_INFO *cs) const
+{
+ return new (thd->mem_root) cmp_item_inet6;
+}
+
+
+
+in_vector *
+Type_handler_inet6::make_in_vector(THD *thd, const Item_func_in *func,
+ uint nargs) const
+{
+ return new (thd->mem_root) in_inet6(thd, nargs);
+}
+
+
+Item *Type_handler_inet6::create_typecast_item(THD *thd, Item *item,
+ const Type_cast_attributes &attr)
+ const
+{
+ return new (thd->mem_root) Item_typecast_inet6(thd, item);
+}
+
+
+Item_cache *Type_handler_inet6::Item_get_cache(THD *thd, const Item *item) const
+{
+ return new (thd->mem_root) Item_cache_inet6(thd);
+}
+
+
+Item *
+Type_handler_inet6::make_const_item_for_comparison(THD *thd,
+ Item *src,
+ const Item *cmp) const
+{
+ Inet6_null tmp(src);
+ if (tmp.is_null())
+ return new (thd->mem_root) Item_null(thd, src->name.str);
+ return new (thd->mem_root) Item_literal_inet6(thd, tmp);
+}
+
+
+Item *Field_inet6::get_equal_const_item(THD *thd, const Context &ctx,
+ Item *const_item)
+{
+ Inet6_null tmp(const_item);
+ if (tmp.is_null())
+ return NULL;
+ return new (thd->mem_root) Item_literal_inet6(thd, tmp);
+}
+
+
+Field *
+Type_handler_inet6::make_table_field_from_def(
+ TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ return new (mem_root) Field_inet6(name, addr);
+}
+
+
+Field *Type_handler_inet6::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *share) const
+{
+ return new (root) Field_inet6(name, addr);
+}
+
+
+Field *Type_handler_inet6::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ const Record_addr tmp(NULL, Bit_addr(true));
+ return new (table->in_use->mem_root) Field_inet6(&empty_clex_str, tmp);
+}
+
+
+bool Type_handler_inet6::partition_field_check(const LEX_CSTRING &field_name,
+ Item *item_expr) const
+{
+ if (item_expr->cmp_type() != STRING_RESULT)
+ {
+ my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0));
+ return true;
+ }
+ return false;
+}
+
+
+bool
+Type_handler_inet6::partition_field_append_value(
+ String *to,
+ Item *item_expr,
+ CHARSET_INFO *field_cs,
+ partition_value_print_mode_t mode)
+ const
+{
+ StringBufferInet6 inet6str;
+ Inet6_null inet6(item_expr);
+ if (inet6.is_null())
+ {
+ my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0));
+ return true;
+ }
+ return inet6.to_string(&inet6str) ||
+ to->append('\'') ||
+ to->append(inet6str) ||
+ to->append('\'');
+}
+
+
+/***************************************************************/
+
+
+class Type_collection_inet: public Type_collection
+{
+ const Type_handler *aggregate_common(const Type_handler *a,
+ const Type_handler *b) const
+ {
+ if (a == b)
+ return a;
+ return NULL;
+ }
+ const Type_handler *aggregate_if_string(const Type_handler *a,
+ const Type_handler *b) const
+ {
+ static const Type_aggregator::Pair agg[]=
+ {
+ {&type_handler_inet6, &type_handler_null, &type_handler_inet6},
+ {&type_handler_inet6, &type_handler_varchar, &type_handler_inet6},
+ {&type_handler_inet6, &type_handler_string, &type_handler_inet6},
+ {&type_handler_inet6, &type_handler_tiny_blob, &type_handler_inet6},
+ {&type_handler_inet6, &type_handler_blob, &type_handler_inet6},
+ {&type_handler_inet6, &type_handler_medium_blob, &type_handler_inet6},
+ {&type_handler_inet6, &type_handler_long_blob, &type_handler_inet6},
+ {&type_handler_inet6, &type_handler_hex_hybrid, &type_handler_inet6},
+ {NULL,NULL,NULL}
+ };
+ return Type_aggregator::find_handler_in_array(agg, a, b, true);
+ }
+public:
+ const Type_handler *aggregate_for_result(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ const Type_handler *h;
+ if ((h= aggregate_common(a, b)) ||
+ (h= aggregate_if_string(a, b)))
+ return h;
+ return NULL;
+ }
+
+ const Type_handler *aggregate_for_min_max(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ return aggregate_for_result(a, b);
+ }
+
+ const Type_handler *aggregate_for_comparison(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ if (const Type_handler *h= aggregate_common(a, b))
+ return h;
+ static const Type_aggregator::Pair agg[]=
+ {
+ {&type_handler_inet6, &type_handler_null, &type_handler_inet6},
+ {&type_handler_inet6, &type_handler_long_blob, &type_handler_inet6},
+ {NULL,NULL,NULL}
+ };
+ return Type_aggregator::find_handler_in_array(agg, a, b, true);
+ }
+
+ const Type_handler *aggregate_for_num_op(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ return NULL;
+ }
+
+ const Type_handler *handler_by_name(const LEX_CSTRING &name) const override
+ {
+ if (type_handler_inet6.name().eq(name))
+ return &type_handler_inet6;
+ return NULL;
+ }
+};
+
+
+const Type_collection *Type_handler_inet6::type_collection() const
+{
+ static Type_collection_inet type_collection_inet;
+ return &type_collection_inet;
+}
diff --git a/plugin/type_inet/sql_type_inet.h b/plugin/type_inet/sql_type_inet.h
new file mode 100644
index 00000000..4de1124f
--- /dev/null
+++ b/plugin/type_inet/sql_type_inet.h
@@ -0,0 +1,1028 @@
+#ifndef SQL_TYPE_INET_H
+#define SQL_TYPE_INET_H
+/* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2014 MariaDB Foundation
+ Copyright (c) 2019 MariaDB Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+
+static const size_t IN_ADDR_SIZE= 4;
+static const size_t IN_ADDR_MAX_CHAR_LENGTH= 15;
+
+static const size_t IN6_ADDR_SIZE= 16;
+static const size_t IN6_ADDR_NUM_WORDS= IN6_ADDR_SIZE / 2;
+
+/**
+ Non-abbreviated syntax is 8 groups, up to 4 digits each,
+ plus 7 delimiters between the groups.
+ Abbreviated syntax is even shorter.
+*/
+static const uint IN6_ADDR_MAX_CHAR_LENGTH= 8 * 4 + 7;
+
+
+class NativeBufferInet6: public NativeBuffer<IN6_ADDR_SIZE+1>
+{
+};
+
+class StringBufferInet6: public StringBuffer<IN6_ADDR_MAX_CHAR_LENGTH+1>
+{
+};
+
+/***********************************************************************/
+
+class Inet4
+{
+ char m_buffer[IN_ADDR_SIZE];
+protected:
+ bool ascii_to_ipv4(const char *str, size_t length);
+ bool character_string_to_ipv4(const char *str, size_t str_length,
+ CHARSET_INFO *cs)
+ {
+ if (cs->state & MY_CS_NONASCII)
+ {
+ char tmp[IN_ADDR_MAX_CHAR_LENGTH];
+ String_copier copier;
+ uint length= copier.well_formed_copy(&my_charset_latin1, tmp, sizeof(tmp),
+ cs, str, str_length);
+ return ascii_to_ipv4(tmp, length);
+ }
+ return ascii_to_ipv4(str, str_length);
+ }
+ bool binary_to_ipv4(const char *str, size_t length)
+ {
+ if (length != sizeof(m_buffer))
+ return true;
+ memcpy(m_buffer, str, length);
+ return false;
+ }
+ // Non-initializing constructor
+ Inet4() { }
+public:
+ void to_binary(char *dst, size_t dstsize) const
+ {
+ DBUG_ASSERT(dstsize >= sizeof(m_buffer));
+ memcpy(dst, m_buffer, sizeof(m_buffer));
+ }
+ bool to_binary(String *to) const
+ {
+ return to->copy(m_buffer, sizeof(m_buffer), &my_charset_bin);
+ }
+ size_t to_string(char *dst, size_t dstsize) const;
+ bool to_string(String *to) const
+ {
+ to->set_charset(&my_charset_latin1);
+ if (to->alloc(INET_ADDRSTRLEN))
+ return true;
+ to->length((uint32) to_string((char*) to->ptr(), INET_ADDRSTRLEN));
+ return false;
+ }
+};
+
+
+class Inet4_null: public Inet4, public Null_flag
+{
+public:
+ // Initialize from a text representation
+ Inet4_null(const char *str, size_t length, CHARSET_INFO *cs)
+ :Null_flag(character_string_to_ipv4(str, length, cs))
+ { }
+ Inet4_null(const String &str)
+ :Inet4_null(str.ptr(), str.length(), str.charset())
+ { }
+ // Initialize from a binary representation
+ Inet4_null(const char *str, size_t length)
+ :Null_flag(binary_to_ipv4(str, length))
+ { }
+ Inet4_null(const Binary_string &str)
+ :Inet4_null(str.ptr(), str.length())
+ { }
+public:
+ const Inet4& to_inet4() const
+ {
+ DBUG_ASSERT(!is_null());
+ return *this;
+ }
+ void to_binary(char *dst, size_t dstsize) const
+ {
+ to_inet4().to_binary(dst, dstsize);
+ }
+ bool to_binary(String *to) const
+ {
+ return to_inet4().to_binary(to);
+ }
+ size_t to_string(char *dst, size_t dstsize) const
+ {
+ return to_inet4().to_string(dst, dstsize);
+ }
+ bool to_string(String *to) const
+ {
+ return to_inet4().to_string(to);
+ }
+};
+
+
+class Inet6
+{
+protected:
+ char m_buffer[IN6_ADDR_SIZE];
+ bool make_from_item(Item *item, bool warn);
+ bool ascii_to_ipv6(const char *str, size_t str_length);
+ bool character_string_to_ipv6(const char *str, size_t str_length,
+ CHARSET_INFO *cs)
+ {
+ if (cs->state & MY_CS_NONASCII)
+ {
+ char tmp[IN6_ADDR_MAX_CHAR_LENGTH];
+ String_copier copier;
+ uint length= copier.well_formed_copy(&my_charset_latin1, tmp, sizeof(tmp),
+ cs, str, str_length);
+ return ascii_to_ipv6(tmp, length);
+ }
+ return ascii_to_ipv6(str, str_length);
+ }
+ bool make_from_character_or_binary_string(const String *str, bool warn);
+ bool binary_to_ipv6(const char *str, size_t length)
+ {
+ if (length != sizeof(m_buffer))
+ return true;
+ memcpy(m_buffer, str, length);
+ return false;
+ }
+
+ Inet6() { }
+
+public:
+ static uint binary_length() { return IN6_ADDR_SIZE; }
+ /**
+ Non-abbreviated syntax is 8 groups, up to 4 digits each,
+ plus 7 delimiters between the groups.
+ Abbreviated syntax is even shorter.
+ */
+ static uint max_char_length() { return IN6_ADDR_MAX_CHAR_LENGTH; }
+
+ static bool only_zero_bytes(const char *ptr, uint length)
+ {
+ for (uint i= 0 ; i < length; i++)
+ {
+ if (ptr[i] != 0)
+ return false;
+ }
+ return true;
+ }
+
+ /*
+ Check at Item's fix_fields() time if "item" can return a nullable value
+ on conversion to INET6, or conversion produces a NOT NULL INET6 value.
+ */
+ static bool fix_fields_maybe_null_on_conversion_to_inet6(Item *item);
+
+public:
+
+ Inet6(Item *item, bool *error, bool warn= true)
+ {
+ *error= make_from_item(item, warn);
+ }
+ void to_binary(char *str, size_t str_size) const
+ {
+ DBUG_ASSERT(str_size >= sizeof(m_buffer));
+ memcpy(str, m_buffer, sizeof(m_buffer));
+ }
+ bool to_binary(String *to) const
+ {
+ return to->copy(m_buffer, sizeof(m_buffer), &my_charset_bin);
+ }
+ bool to_native(Native *to) const
+ {
+ return to->copy(m_buffer, sizeof(m_buffer));
+ }
+ size_t to_string(char *dst, size_t dstsize) const;
+ bool to_string(String *to) const
+ {
+ to->set_charset(&my_charset_latin1);
+ if (to->alloc(INET6_ADDRSTRLEN))
+ return true;
+ to->length((uint32) to_string((char*) to->ptr(), INET6_ADDRSTRLEN));
+ return false;
+ }
+ bool is_v4compat() const
+ {
+ static_assert(sizeof(in6_addr) == IN6_ADDR_SIZE, "unexpected in6_addr size");
+ return IN6_IS_ADDR_V4COMPAT((struct in6_addr *) m_buffer);
+ }
+ bool is_v4mapped() const
+ {
+ static_assert(sizeof(in6_addr) == IN6_ADDR_SIZE, "unexpected in6_addr size");
+ return IN6_IS_ADDR_V4MAPPED((struct in6_addr *) m_buffer);
+ }
+ int cmp(const char *str, size_t length) const
+ {
+ DBUG_ASSERT(length == sizeof(m_buffer));
+ return memcmp(m_buffer, str, length);
+ }
+ int cmp(const Binary_string &other) const
+ {
+ return cmp(other.ptr(), other.length());
+ }
+ int cmp(const Inet6 &other) const
+ {
+ return memcmp(m_buffer, other.m_buffer, sizeof(m_buffer));
+ }
+};
+
+
+class Inet6_zero: public Inet6
+{
+public:
+ Inet6_zero()
+ {
+ bzero(&m_buffer, sizeof(m_buffer));
+ }
+};
+
+
+class Inet6_null: public Inet6, public Null_flag
+{
+public:
+ // Initialize from a text representation
+ Inet6_null(const char *str, size_t length, CHARSET_INFO *cs)
+ :Null_flag(character_string_to_ipv6(str, length, cs))
+ { }
+ Inet6_null(const String &str)
+ :Inet6_null(str.ptr(), str.length(), str.charset())
+ { }
+ // Initialize from a binary representation
+ Inet6_null(const char *str, size_t length)
+ :Null_flag(binary_to_ipv6(str, length))
+ { }
+ Inet6_null(const Binary_string &str)
+ :Inet6_null(str.ptr(), str.length())
+ { }
+ // Initialize from an Item
+ Inet6_null(Item *item, bool warn= true)
+ :Null_flag(make_from_item(item, warn))
+ { }
+public:
+ const Inet6& to_inet6() const
+ {
+ DBUG_ASSERT(!is_null());
+ return *this;
+ }
+ void to_binary(char *str, size_t str_size) const
+ {
+ to_inet6().to_binary(str, str_size);
+ }
+ bool to_binary(String *to) const
+ {
+ return to_inet6().to_binary(to);
+ }
+ size_t to_string(char *dst, size_t dstsize) const
+ {
+ return to_inet6().to_string(dst, dstsize);
+ }
+ bool to_string(String *to) const
+ {
+ return to_inet6().to_string(to);
+ }
+ bool is_v4compat() const
+ {
+ return to_inet6().is_v4compat();
+ }
+ bool is_v4mapped() const
+ {
+ return to_inet6().is_v4mapped();
+ }
+};
+
+
+class Type_std_attributes_inet6: public Type_std_attributes
+{
+public:
+ Type_std_attributes_inet6()
+ :Type_std_attributes(
+ Type_numeric_attributes(Inet6::max_char_length(), 0, true),
+ DTCollation_numeric())
+ { }
+};
+
+
+class Type_handler_inet6: public Type_handler
+{
+ bool character_or_binary_string_to_native(THD *thd, const String *str,
+ Native *to) const;
+public:
+ ~Type_handler_inet6() override {}
+
+ const Type_collection *type_collection() const override;
+ const Name &default_value() const override
+ {
+ static Name def(STRING_WITH_LEN("::"));
+ return def;
+ }
+ protocol_send_type_t protocol_send_type() const override
+ {
+ return PROTOCOL_SEND_STRING;
+ }
+ bool Item_append_extended_type_info(Send_field_extended_metadata *to,
+ const Item *item) const override
+ {
+ return to->set_data_type_name(name().lex_cstring());
+ }
+
+ enum_field_types field_type() const override
+ {
+ return MYSQL_TYPE_STRING;
+ }
+
+ Item_result result_type() const override
+ {
+ return STRING_RESULT;
+ }
+
+ Item_result cmp_type() const override
+ {
+ return STRING_RESULT;
+ }
+
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr)
+ const override
+ {
+ return DYN_COL_STRING;
+ }
+
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ {
+ return Inet6::max_char_length();
+ }
+
+ const Type_handler *type_handler_for_comparison() const override
+ {
+ return this;
+ }
+
+ int
+ stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const override
+ {
+ DBUG_ASSERT(field->type_handler() == this);
+ Inet6_null ni(item); // Convert Item to INET6
+ if (ni.is_null())
+ return 0;
+ NativeBufferInet6 tmp;
+ if (field->val_native(&tmp))
+ {
+ DBUG_ASSERT(0);
+ return 0;
+ }
+ return -ni.cmp(tmp);
+ }
+ CHARSET_INFO *charset_for_protocol(const Item *item) const override
+ {
+ return item->collation.collation;
+ }
+
+ bool is_scalar_type() const override { return true; }
+ bool is_val_native_ready() const override { return true; }
+ bool can_return_int() const override { return false; }
+ bool can_return_decimal() const override { return false; }
+ bool can_return_real() const override { return false; }
+ bool can_return_str() const override { return true; }
+ bool can_return_text() const override { return true; }
+ bool can_return_date() const override { return false; }
+ bool can_return_time() const override { return false; }
+ bool convert_to_binary_using_val_native() const override { return true; }
+
+ uint Item_time_precision(THD *thd, Item *item) const override
+ {
+ return 0;
+ }
+ uint Item_datetime_precision(THD *thd, Item *item) const override
+ {
+ return 0;
+ }
+ uint Item_decimal_scale(const Item *item) const override
+ {
+ return 0;
+ }
+ uint Item_decimal_precision(const Item *item) const override
+ {
+ /*
+ This will be needed if we ever allow cast from INET6 to DECIMAL.
+ Decimal precision of INET6 is 39 digits:
+ 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' =
+ 340282366920938463463374607431768211456 = 39 digits
+ */
+ return 39;
+ }
+
+ /*
+ Returns how many digits a divisor adds into a division result.
+ See Item::divisor_precision_increment() in item.h for more comments.
+ */
+ uint Item_divisor_precision_increment(const Item *) const override
+ {
+ return 0;
+ }
+ /**
+ Makes a temporary table Field to handle numeric aggregate functions,
+ e.g. SUM(DISTINCT expr), AVG(DISTINCT expr), etc.
+ */
+ Field *make_num_distinct_aggregator_field(MEM_ROOT *,
+ const Item *) const override
+ {
+ DBUG_ASSERT(0);
+ return 0;
+ }
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *TABLE,
+ uint metadata,
+ const Field *target) const override;
+ // Fix attributes after the parser
+ bool Column_definition_fix_attributes(Column_definition *c) const override
+ {
+ c->length= Inet6::max_char_length();
+ return false;
+ }
+
+ bool Column_definition_prepare_stage1(THD *thd,
+ MEM_ROOT *mem_root,
+ Column_definition *def,
+ handler *file,
+ ulonglong table_flags,
+ const Column_derived_attributes
+ *derived_attr)
+ const override
+ {
+ def->prepare_stage1_simple(&my_charset_numeric);
+ return false;
+ }
+
+ bool Column_definition_redefine_stage1(Column_definition *def,
+ const Column_definition *dup,
+ const handler *file)
+ const override
+ {
+ def->redefine_stage1_common(dup, file);
+ def->set_compression_method(dup->compression_method());
+ def->create_length_to_internal_length_string();
+ return false;
+ }
+
+ bool Column_definition_prepare_stage2(Column_definition *def,
+ handler *file,
+ ulonglong table_flags) const override
+ {
+ def->pack_flag= FIELDFLAG_BINARY;
+ return false;
+ }
+
+ bool partition_field_check(const LEX_CSTRING &field_name,
+ Item *item_expr) const override;
+
+ bool partition_field_append_value(String *to,
+ Item *item_expr,
+ CHARSET_INFO *field_cs,
+ partition_value_print_mode_t mode)
+ const override;
+
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE_SHARE *table) const override;
+
+ Field *
+ make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const override;
+ void
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const override
+ {
+ def->frm_pack_basic(buff);
+ def->frm_pack_charset(buff);
+ }
+ bool
+ Column_definition_attributes_frm_unpack(Column_definition_attributes *def,
+ TABLE_SHARE *share,
+ const uchar *buffer,
+ LEX_CUSTRING *gis_options)
+ const override
+ {
+ def->frm_unpack_basic(buffer);
+ return def->frm_unpack_charset(share, buffer);
+ }
+ void make_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param)
+ const override;
+ uint make_packed_sort_key_part(uchar *to, Item *item,
+ const SORT_FIELD_ATTR *sort_field,
+ Sort_param *param) const override;
+ void sort_length(THD *thd,
+ const Type_std_attributes *item,
+ SORT_FIELD_ATTR *attr) const override;
+ uint32 max_display_length(const Item *item) const override
+ {
+ return Inet6::max_char_length();
+ }
+ uint32 calc_pack_length(uint32 length) const override
+ {
+ return Inet6::binary_length();
+ }
+ void Item_update_null_value(Item *item) const override
+ {
+ NativeBufferInet6 tmp;
+ item->val_native(current_thd, &tmp);
+ }
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override;
+ void Item_param_setup_conversion(THD *thd, Item_param *param) const override;
+ void Item_param_set_param_func(Item_param *param,
+ uchar **pos, ulong len) const override
+ {
+ param->set_param_str(pos, len);
+ }
+ bool Item_param_set_from_value(THD *thd,
+ Item_param *param,
+ const Type_all_attributes *attr,
+ const st_value *val) const override
+ {
+ param->unsigned_flag= false;//QQ
+ param->setup_conversion_string(thd, attr->collation.collation);
+ /*
+ Exact value of max_length is not known unless data is converted to
+ charset of connection, so we have to set it later.
+ */
+ return param->set_str(val->m_string.ptr(), val->m_string.length(),
+ attr->collation.collation,
+ attr->collation.collation);
+ }
+ bool Item_param_val_native(THD *thd, Item_param *item, Native *to)
+ const override
+ {
+ StringBufferInet6 buffer;
+ String *str= item->val_str(&buffer);
+ if (!str)
+ return true;
+ Inet6_null tmp(*str);
+ return tmp.is_null() || tmp.to_native(to);
+ }
+ bool Item_send(Item *item, Protocol *p, st_value *buf) const override
+ {
+ return Item_send_str(item, p, buf);
+ }
+ int Item_save_in_field(Item *item, Field *field, bool no_conversions)
+ const override
+ {
+ if (field->type_handler() == this)
+ {
+ NativeBuffer<MAX_FIELD_WIDTH> tmp;
+ bool rc= item->val_native(current_thd, &tmp);
+ if (rc || item->null_value)
+ return set_field_to_null_with_conversions(field, no_conversions);
+ field->set_notnull();
+ return field->store_native(tmp);
+ }
+ return item->save_str_in_field(field, no_conversions);
+ }
+
+ String *print_item_value(THD *thd, Item *item, String *str) const override
+ {
+ StringBufferInet6 buf;
+ String *result= item->val_str(&buf);
+ /*
+ TODO: This should eventually use one of these notations:
+ 1. CAST('::' AS INET6)
+ Problem: CAST is not supported as a NAME_CONST() argument.
+ 2. INET6'::
+ Problem: This syntax is not supported by the parser yet.
+ */
+ return !result ||
+ str->realloc(result->length() + 2) ||
+ str->append(STRING_WITH_LEN("'")) ||
+ str->append(result->ptr(), result->length()) ||
+ str->append(STRING_WITH_LEN("'")) ?
+ NULL :
+ str;
+ }
+
+ /**
+ Check if
+ WHERE expr=value AND expr=const
+ can be rewritten as:
+ WHERE const=value AND expr=const
+
+ "this" is the comparison handler that is used by "target".
+
+ @param target - the predicate expr=value,
+ whose "expr" argument will be replaced to "const".
+ @param target_expr - the target's "expr" which will be replaced to "const".
+ @param target_value - the target's second argument, it will remain unchanged.
+ @param source - the equality predicate expr=const (or expr<=>const)
+ that can be used to rewrite the "target" part
+ (under certain conditions, see the code).
+ @param source_expr - the source's "expr". It should be exactly equal to
+ the target's "expr" to make condition rewrite possible.
+ @param source_const - the source's "const" argument, it will be inserted
+ into "target" instead of "expr".
+ */
+ bool
+ can_change_cond_ref_to_const(Item_bool_func2 *target,
+ Item *target_expr, Item *target_value,
+ Item_bool_func2 *source,
+ Item *source_expr, Item *source_const)
+ const override
+ {
+ /*
+ WHERE COALESCE(inet6_col)='::1' AND COALESCE(inet6_col)=CONCAT(a); -->
+ WHERE COALESCE(inet6_col)='::1' AND '::1'=CONCAT(a);
+ */
+ return target->compare_type_handler() == source->compare_type_handler();
+ }
+ bool
+ subquery_type_allows_materialization(const Item *inner,
+ const Item *outer, bool) const override
+ {
+ /*
+ Example:
+ SELECT * FROM t1 WHERE a IN (SELECT inet6col FROM t1 GROUP BY inet6col);
+ Allow materialization only if the outer column is also INET6.
+ This can be changed for more relaxed rules in the future.
+ */
+ DBUG_ASSERT(inner->type_handler() == this);
+ return outer->type_handler() == this;
+ }
+ /**
+ Make a simple constant replacement item for a constant "src",
+ so the new item can futher be used for comparison with "cmp", e.g.:
+ src = cmp -> replacement = cmp
+
+ "this" is the type handler that is used to compare "src" and "cmp".
+
+ @param thd - current thread, for mem_root
+ @param src - The item that we want to replace. It's a const item,
+ but it can be complex enough to calculate on every row.
+ @param cmp - The src's comparand.
+ @retval - a pointer to the created replacement Item
+ @retval - NULL, if could not create a replacement (e.g. on EOM).
+ NULL is also returned for ROWs, because instead of replacing
+ a Item_row to a new Item_row, Type_handler_row just replaces
+ its elements.
+ */
+ Item *make_const_item_for_comparison(THD *thd,
+ Item *src,
+ const Item *cmp) const override;
+ Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
+
+ Item *create_typecast_item(THD *thd, Item *item,
+ const Type_cast_attributes &attr) const override;
+
+ int cmp_native(const Native &a, const Native &b) const override
+ {
+ DBUG_ASSERT(a.length() == Inet6::binary_length());
+ DBUG_ASSERT(b.length() == Inet6::binary_length());
+ return memcmp(a.ptr(), b.ptr(), Inet6::binary_length());
+ }
+ bool set_comparator_func(Arg_comparator *cmp) const override
+ {
+ return cmp->set_cmp_func_native();
+ }
+ bool Item_const_eq(const Item_const *a, const Item_const *b,
+ bool binary_cmp) const override
+ {
+ return false;//QQ
+ }
+ bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
+ Item *a, Item *b) const override
+ {
+ Inet6_null na(a);
+ Inet6_null nb(b);
+ return !na.is_null() && !nb.is_null() && !na.cmp(nb);
+ }
+ bool Item_hybrid_func_fix_attributes(THD *thd,
+ const char *name,
+ Type_handler_hybrid_field_type *h,
+ Type_all_attributes *attr,
+ Item **items,
+ uint nitems) const override
+ {
+ attr->Type_std_attributes::operator=(Type_std_attributes_inet6());
+ h->set_handler(this);
+ /*
+ If some of the arguments cannot be safely converted to "INET6 NOT NULL",
+ then mark the entire function nullability as NULL-able.
+ Otherwise, keep the generic nullability calculated by earlier stages:
+ - either by the most generic way in Item_func::fix_fields()
+ - or by Item_func_xxx::fix_length_and_dec() before the call of
+ Item_hybrid_func_fix_attributes()
+ IFNULL() is special. It does not need to test args[0].
+ */
+ uint first= dynamic_cast<Item_func_ifnull*>(attr) ? 1 : 0;
+ for (uint i= first; i < nitems; i++)
+ {
+ if (Inet6::fix_fields_maybe_null_on_conversion_to_inet6(items[i]))
+ {
+ attr->set_maybe_null(true);
+ break;
+ }
+ }
+ return false;
+ }
+ bool Item_func_min_max_fix_attributes(THD *thd,
+ Item_func_min_max *func,
+ Item **items,
+ uint nitems) const override
+ {
+ return Item_hybrid_func_fix_attributes(thd, func->func_name(),
+ func, func, items, nitems);
+
+ }
+ bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const override
+ {
+ func->Type_std_attributes::operator=(Type_std_attributes_inet6());
+ func->set_handler(this);
+ return false;
+ }
+ bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *func) const override
+ {
+ return Item_func_or_sum_illegal_param(func);
+ }
+ bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *func) const override
+ {
+ return Item_func_or_sum_illegal_param(func);
+ }
+ bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *func) const override
+ {
+ return Item_func_or_sum_illegal_param(func);
+ }
+
+ bool Item_val_native_with_conversion(THD *thd, Item *item,
+ Native *to) const override
+ {
+ if (item->type_handler() == this)
+ return item->val_native(thd, to); // No conversion needed
+ StringBufferInet6 buffer;
+ String *str= item->val_str(&buffer);
+ return str ? character_or_binary_string_to_native(thd, str, to) : true;
+ }
+ bool Item_val_native_with_conversion_result(THD *thd, Item *item,
+ Native *to) const override
+ {
+ if (item->type_handler() == this)
+ return item->val_native_result(thd, to); // No conversion needed
+ StringBufferInet6 buffer;
+ String *str= item->str_result(&buffer);
+ return str ? character_or_binary_string_to_native(thd, str, to) : true;
+ }
+
+ bool Item_val_bool(Item *item) const override
+ {
+ NativeBufferInet6 tmp;
+ if (item->val_native(current_thd, &tmp))
+ return false;
+ return !Inet6::only_zero_bytes(tmp.ptr(), tmp.length());
+ }
+ void Item_get_date(THD *thd, Item *item,
+ Temporal::Warn *buff, MYSQL_TIME *ltime,
+ date_mode_t fuzzydate) const override
+ {
+ set_zero_time(ltime, MYSQL_TIMESTAMP_TIME);
+ }
+
+ longlong Item_val_int_signed_typecast(Item *item) const override
+ {
+ DBUG_ASSERT(0);
+ return 0;
+ }
+
+ longlong Item_val_int_unsigned_typecast(Item *item) const override
+ {
+ DBUG_ASSERT(0);
+ return 0;
+ }
+
+ String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str)
+ const override
+ {
+ NativeBufferInet6 tmp;
+ if ((item->null_value= item->arguments()[0]->val_native(current_thd, &tmp)))
+ return NULL;
+ DBUG_ASSERT(tmp.length() == Inet6::binary_length());
+ if (str->set_hex(tmp.ptr(), tmp.length()))
+ {
+ str->length(0);
+ str->set_charset(item->collation.collation);
+ }
+ return str;
+ }
+
+ String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *item,
+ String *str) const override
+ {
+ NativeBufferInet6 native;
+ if (item->val_native(current_thd, &native))
+ {
+ DBUG_ASSERT(item->null_value);
+ return NULL;
+ }
+ DBUG_ASSERT(native.length() == Inet6::binary_length());
+ Inet6_null tmp(native.ptr(), native.length());
+ return tmp.is_null() || tmp.to_string(str) ? NULL : str;
+ }
+ double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *)
+ const override
+ {
+ return 0;
+ }
+ longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *)
+ const override
+ {
+ return 0;
+ }
+ my_decimal *
+ Item_func_hybrid_field_type_val_decimal(Item_func_hybrid_field_type *,
+ my_decimal *to) const override
+ {
+ my_decimal_set_zero(to);
+ return to;
+ }
+ void Item_func_hybrid_field_type_get_date(THD *,
+ Item_func_hybrid_field_type *,
+ Temporal::Warn *,
+ MYSQL_TIME *to,
+ date_mode_t fuzzydate)
+ const override
+ {
+ set_zero_time(to, MYSQL_TIMESTAMP_TIME);
+ }
+ // WHERE is Item_func_min_max_val_native???
+ String *Item_func_min_max_val_str(Item_func_min_max *func, String *str)
+ const override
+ {
+ Inet6_null tmp(func);
+ return tmp.is_null() || tmp.to_string(str) ? NULL : str;
+ }
+ double Item_func_min_max_val_real(Item_func_min_max *) const override
+ {
+ return 0;
+ }
+ longlong Item_func_min_max_val_int(Item_func_min_max *) const override
+ {
+ return 0;
+ }
+ my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
+ my_decimal *to) const override
+ {
+ my_decimal_set_zero(to);
+ return to;
+ }
+ bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*,
+ MYSQL_TIME *to, date_mode_t fuzzydate)
+ const override
+ {
+ set_zero_time(to, MYSQL_TIMESTAMP_TIME);
+ return false;
+ }
+
+ bool
+ Item_func_between_fix_length_and_dec(Item_func_between *func) const override
+ {
+ return false;
+ }
+ longlong Item_func_between_val_int(Item_func_between *func) const override
+ {
+ return func->val_int_cmp_native();
+ }
+
+ cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override;
+
+ in_vector *make_in_vector(THD *thd, const Item_func_in *func,
+ uint nargs) const override;
+
+ bool Item_func_in_fix_comparator_compatible_types(THD *thd,
+ Item_func_in *func)
+ const override
+ {
+ if (func->compatible_types_scalar_bisection_possible())
+ {
+ return func->value_list_convert_const_to_int(thd) ||
+ func->fix_for_scalar_comparison_using_bisection(thd);
+ }
+ return
+ func->fix_for_scalar_comparison_using_cmp_items(thd,
+ 1U << (uint) STRING_RESULT);
+ }
+ bool
+ Item_func_round_fix_length_and_dec(Item_func_round *func) const override
+ {
+ return Item_func_or_sum_illegal_param(func);
+ }
+ bool
+ Item_func_int_val_fix_length_and_dec(Item_func_int_val *func) const override
+ {
+ return Item_func_or_sum_illegal_param(func);
+ }
+
+ bool Item_func_abs_fix_length_and_dec(Item_func_abs *func) const override
+ {
+ return Item_func_or_sum_illegal_param(func);
+ }
+
+ bool Item_func_neg_fix_length_and_dec(Item_func_neg *func) const override
+ {
+ return Item_func_or_sum_illegal_param(func);
+ }
+
+ bool
+ Item_func_signed_fix_length_and_dec(Item_func_signed *item) const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+ bool
+ Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+ bool
+ Item_double_typecast_fix_length_and_dec(Item_double_typecast *item)
+ const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+ bool
+ Item_float_typecast_fix_length_and_dec(Item_float_typecast *item)
+ const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+ bool
+ Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *item)
+ const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+ bool
+ Item_char_typecast_fix_length_and_dec(Item_char_typecast *item)
+ const override;
+ bool
+ Item_time_typecast_fix_length_and_dec(Item_time_typecast *item) const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+ bool
+ Item_date_typecast_fix_length_and_dec(Item_date_typecast *item) const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+ bool
+ Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *item)
+ const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+ bool
+ Item_func_plus_fix_length_and_dec(Item_func_plus *item) const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+ bool
+ Item_func_minus_fix_length_and_dec(Item_func_minus *item) const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+ bool
+ Item_func_mul_fix_length_and_dec(Item_func_mul *item) const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+ bool
+ Item_func_div_fix_length_and_dec(Item_func_div *item) const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+ bool
+ Item_func_mod_fix_length_and_dec(Item_func_mod *item) const override
+ {
+ return Item_func_or_sum_illegal_param(item);
+ }
+};
+
+
+extern MYSQL_PLUGIN_IMPORT Type_handler_inet6 type_handler_inet6;
+
+
+#endif /* SQL_TYPE_INET_H */
diff --git a/plugin/type_mysql_json/CMakeLists.txt b/plugin/type_mysql_json/CMakeLists.txt
new file mode 100644
index 00000000..ac0a1783
--- /dev/null
+++ b/plugin/type_mysql_json/CMakeLists.txt
@@ -0,0 +1,18 @@
+# Copyright (c) 2020, MariaDB Foundation.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+MYSQL_ADD_PLUGIN(type_mysql_json
+ mysql_json.cc type.cc
+ MODULE_ONLY RECOMPILE_FOR_EMBEDDED)
diff --git a/plugin/type_mysql_json/mysql_json.cc b/plugin/type_mysql_json/mysql_json.cc
new file mode 100644
index 00000000..4a75cae3
--- /dev/null
+++ b/plugin/type_mysql_json/mysql_json.cc
@@ -0,0 +1,515 @@
+/*
+ Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2020 MariaDB Foundation
+
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "mysql_json.h"
+#include "my_global.h"
+#include "compat56.h"
+#include "my_decimal.h"
+#include "sql_time.h"
+
+static void TIME_from_longlong_date_packed(MYSQL_TIME *ltime, longlong tmp)
+{
+ TIME_from_longlong_datetime_packed(ltime, tmp);
+ ltime->time_type= MYSQL_TIMESTAMP_DATE;
+}
+
+
+/*
+ Json values in MySQL comprises the standard set of JSON values plus a MySQL
+ specific set. A JSON number type is subdivided into int, uint, double and
+ decimal.
+
+ MySQL also adds four built-in date/time values: date, time, datetime and
+ timestamp. An additional opaque value can store any other MySQL type.
+*/
+
+enum JSONB_LITERAL_TYPES {
+ JSONB_NULL_LITERAL= 0x0,
+ JSONB_TRUE_LITERAL= 0x1,
+ JSONB_FALSE_LITERAL= 0x2,
+};
+
+/*
+ The size of offset or size fields in the small and the large storage
+ format for JSON objects and JSON arrays.
+*/
+static const uchar SMALL_OFFSET_SIZE= 2;
+static const uchar LARGE_OFFSET_SIZE= 4;
+
+/*
+ The size of key entries for objects when using the small storage
+ format or the large storage format. In the small format it is 4
+ bytes (2 bytes for key length and 2 bytes for key offset). In the
+ large format it is 6 (2 bytes for length, 4 bytes for offset).
+*/
+static const uchar KEY_ENTRY_SIZE_SMALL= (2 + SMALL_OFFSET_SIZE);
+static const uchar KEY_ENTRY_SIZE_LARGE= (2 + LARGE_OFFSET_SIZE);
+
+/*
+ The size of value entries for objects or arrays. When using the
+ small storage format, the entry size is 3 (1 byte for type, 2 bytes
+ for offset). When using the large storage format, it is 5 (1 byte
+ for type, 4 bytes for offset).
+*/
+static const uchar VALUE_ENTRY_SIZE_SMALL= (1 + SMALL_OFFSET_SIZE);
+static const uchar VALUE_ENTRY_SIZE_LARGE= (1 + LARGE_OFFSET_SIZE);
+
+/* The maximum number of nesting levels allowed in a JSON document. */
+static const uchar JSON_DOCUMENT_MAX_DEPTH= 150;
+
+/**
+ Read an offset or size field from a buffer. The offset could be either
+ a two byte unsigned integer or a four byte unsigned integer.
+
+ @param data the buffer to read from
+ @param large tells if the large or small storage format is used; true
+ means read four bytes, false means read two bytes
+*/
+static inline size_t read_offset_or_size(const uchar *data, bool large)
+{
+ return large ? uint4korr(data) : uint2korr(data);
+}
+
+static inline size_t key_size(bool large)
+{
+ return large ? KEY_ENTRY_SIZE_LARGE : KEY_ENTRY_SIZE_SMALL;
+}
+
+static inline size_t value_size(bool large)
+{
+ return large ? VALUE_ENTRY_SIZE_LARGE : VALUE_ENTRY_SIZE_SMALL;
+}
+
+/**
+ Inlined values are a space optimization. The actual value is stored
+ instead of the offset pointer to the location where a non-inlined
+ value would be located.
+
+ @param[in] type The type to check.
+ @param[in] large tells if the large or small storage format is used;
+*/
+static inline bool type_is_stored_inline(JSONB_TYPES type, bool large)
+{
+ return (type == JSONB_TYPE_INT16 ||
+ type == JSONB_TYPE_UINT16 ||
+ type == JSONB_TYPE_LITERAL ||
+ (large && (type == JSONB_TYPE_INT32 ||
+ type == JSONB_TYPE_UINT32)));
+}
+
+/**
+ Read a variable length integer. A variable length integer uses the 8th bit in
+ each byte to mark if there are more bytes needed to store the integer. The
+ other 7 bits in the byte are used to store the actual integer's bits.
+
+ @param[in] data the buffer to read from
+ @param[in] data_length the maximum number of bytes to read from data
+ @param[out] length the length that was read
+ @param[out] num the number of bytes needed to represent the length
+ @return false on success, true on error
+*/
+static inline bool read_variable_length(const uchar *data, size_t data_length,
+ size_t *length, size_t *num)
+{
+ /*
+ It takes five bytes to represent UINT_MAX32, which is the largest
+ supported length, so don't look any further.
+
+ Use data_length as max value to prevent segfault when reading a corrupted
+ JSON document.
+ */
+ const size_t MAX_BYTES= MY_MIN(data_length, 5);
+ size_t len= 0;
+ for (size_t i= 0; i < MAX_BYTES; i++)
+ {
+ /* Get the next 7 bits of the length. */
+ len|= (data[i] & 0x7f) << (7 * i);
+ if ((data[i] & 0x80) == 0)
+ {
+ /* The length shouldn't exceed 32 bits. */
+ if (len > UINT_MAX32)
+ return true;
+
+ /* This was the last byte. Return successfully. */
+ *num= i + 1;
+ *length= len;
+ return false;
+ }
+ }
+
+ /* No more available bytes. Return true to signal error. This implies a
+ corrupted JSON document. */
+ return true;
+}
+
+/**
+ JSON formatting in MySQL escapes a few special characters to prevent
+ ambiguity.
+*/
+static bool append_string_json(String *buffer, const uchar *data, size_t len)
+{
+ const uchar *last= data + len;
+ for (; data < last; data++)
+ {
+ const uchar c= *data;
+ switch (c) {
+ case '\\':
+ buffer->append("\\\\");
+ break;
+ case '\n':
+ buffer->append("\\n");
+ break;
+ case '\r':
+ buffer->append("\\r");
+ break;
+ case '"':
+ buffer->append("\\\"");
+ break;
+ case '\b':
+ buffer->append("\\b");
+ break;
+ case '\f':
+ buffer->append("\\f");
+ break;
+ case '\t':
+ buffer->append("\\t");
+ break;
+ default:
+ buffer->append(c);
+ break;
+ }
+ }
+ return false;
+}
+
+/*
+ Function used for JSON_OPAQUE type.
+*/
+static bool print_mysql_datetime_value(String *buffer, enum_field_types type,
+ const uchar *data, size_t len)
+{
+ if (len < 8)
+ return true;
+
+ MYSQL_TIME t;
+ switch (type)
+ {
+ case MYSQL_TYPE_TIME:
+ TIME_from_longlong_time_packed(&t, sint8korr(data));
+ break;
+ case MYSQL_TYPE_DATE:
+ TIME_from_longlong_date_packed(&t, sint8korr(data));
+ break;
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_TIMESTAMP:
+ TIME_from_longlong_datetime_packed(&t, sint8korr(data));
+ break;
+ default:
+ DBUG_ASSERT(0);
+ return true;
+ }
+ /* Wrap all datetime strings within double quotes. */
+ buffer->append('\"');
+ buffer->reserve(MAX_DATE_STRING_REP_LENGTH);
+ buffer->length(buffer->length() +
+ my_TIME_to_str(&t, const_cast<char *>(buffer->end()), 6));
+ buffer->append('\"');
+ return false;
+}
+
+static bool parse_mysql_scalar(String *buffer, size_t value_json_type,
+ const uchar *data, size_t len)
+{
+ switch (value_json_type) {
+ case JSONB_TYPE_LITERAL:
+ {
+ if (len < 1)
+ return true;
+ switch (static_cast<JSONB_LITERAL_TYPES>(*data)) {
+ case JSONB_NULL_LITERAL:
+ return buffer->append("null");
+ case JSONB_TRUE_LITERAL:
+ return buffer->append("true");
+ case JSONB_FALSE_LITERAL:
+ return buffer->append("false");
+ default: /* Invalid literal constant, malformed JSON. */
+ return true;
+ }
+ }
+ case JSONB_TYPE_INT16:
+ return len < 2 || buffer->append_longlong(sint2korr(data));
+ case JSONB_TYPE_INT32:
+ return len < 4 || buffer->append_longlong(sint4korr(data));
+ case JSONB_TYPE_INT64:
+ return len < 8 || buffer->append_longlong(sint8korr(data));
+ case JSONB_TYPE_UINT16:
+ return len < 2 || buffer->append_ulonglong(uint2korr(data));
+ case JSONB_TYPE_UINT32:
+ return len < 4 || buffer->append_ulonglong(uint4korr(data));
+ case JSONB_TYPE_UINT64:
+ return len < 8 || buffer->append_ulonglong(uint8korr(data));
+ case JSONB_TYPE_DOUBLE:
+ if (len < 8)
+ return true;
+ buffer->reserve(FLOATING_POINT_BUFFER, 2 * FLOATING_POINT_BUFFER);
+ buffer->qs_append(reinterpret_cast<const double *>(data));
+ return false;
+ case JSONB_TYPE_STRING:
+ {
+ size_t string_length, store_bytes;
+
+ return read_variable_length(data, len, &string_length, &store_bytes) ||
+ len < store_bytes + string_length ||
+ buffer->append('"') ||
+ append_string_json(buffer, data + store_bytes, string_length) ||
+ buffer->append('"');
+ }
+ case JSONB_TYPE_OPAQUE:
+ {
+ /* The field_type maps directly to enum_field_types. */
+ const uchar type_value= *data;
+ const enum_field_types field_type= static_cast<enum_field_types>(type_value);
+
+ size_t UNINIT_VAR(blob_length), length_bytes;
+ const uchar *blob_start;
+
+ if (read_variable_length(data + 1, len, &blob_length, &length_bytes) ||
+ len < length_bytes + blob_length)
+ return true;
+ blob_start= data + length_bytes + 1;
+
+ switch (field_type) {
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_TIMESTAMP:
+ return print_mysql_datetime_value(buffer, field_type,
+ blob_start, blob_length);
+ case MYSQL_TYPE_NEWDECIMAL:
+ {
+ /* Expect at least two bytes, which contain precision and scale. */
+ if (blob_length < 2)
+ return true;
+
+ const int precision= blob_start[0];
+ const int scale= blob_start[1];
+
+ my_decimal d;
+
+ /* The decimal value is encoded after the two prec/scale bytes. */
+ const size_t dec_size= my_decimal_get_binary_size(precision, scale);
+ if (dec_size != blob_length - 2 ||
+ binary2my_decimal(E_DEC_ERROR,
+ reinterpret_cast<const uchar *>(blob_start + 2),
+ &d, precision, scale) != E_DEC_OK)
+ return true;
+
+ if (d.to_string_native(buffer, 0, 0, ' ', E_DEC_ERROR) != E_DEC_OK)
+ return true;
+ return false;
+ }
+ default:
+ {
+ /* Any other MySQL type is presented as a base64 encoded string. */
+ if (buffer->append("\"base64:type") ||
+ buffer->append_longlong(field_type) ||
+ buffer->append(':'))
+ return true;
+
+ const size_t needed= my_base64_needed_encoded_length(
+ static_cast<int>(blob_length));
+ if (buffer->reserve(needed) ||
+ my_base64_encode(blob_start, blob_length,
+ const_cast<char*>(buffer->end())))
+ return true;
+ /* -1 to override the null terminator from my_base64_encode */
+ DBUG_ASSERT(*(buffer->end() + needed) == '\0');
+ buffer->length(buffer->length() + needed - 1);
+ return buffer->append('"');
+ }
+ }
+ }
+ default:
+ return true;
+ }
+}
+
+
+/**
+ Read a value from a JSON Object or Array, given the position of it.
+ This function handles both inlined values as well as values stored at
+ an offset.
+
+ @param[out] buffer Where to print the results.
+ @param[in] data The raw binary data of the Object or Array.
+ @param[in] len The length of the binary data.
+ @param[in] value_type_offset Where the type of the value is stored.
+ @param[in] large true if the large storage format is used;
+ @param[in] depth How deep the JSON object is in the hierarchy.
+*/
+static bool parse_mysql_scalar_or_value(String *buffer, const uchar *data,
+ size_t len, size_t value_type_offset,
+ bool large, size_t depth)
+{
+ /* Get the type of the value stored at the key. */
+ const JSONB_TYPES value_type=
+ static_cast<JSONB_TYPES>(data[value_type_offset]);
+
+ if (type_is_stored_inline(value_type, large))
+ {
+ const size_t value_start = value_type_offset + 1;
+ if (parse_mysql_scalar(buffer, value_type, data + value_start,
+ len - value_start))
+ return true;
+ }
+ else
+ {
+ /* The offset to where the value is stored is relative to the start
+ of the Object / Array */
+ const size_t value_start= read_offset_or_size(
+ data + value_type_offset + 1, large);
+ if (parse_mysql_json_value(buffer, value_type, data + value_start,
+ len - value_start, depth))
+ return true;
+ }
+ return false;
+}
+
+static bool parse_array_or_object(String *buffer, const uchar *data, size_t len,
+ bool handle_as_object, bool large,
+ size_t depth)
+{
+ if (++depth > JSON_DOCUMENT_MAX_DEPTH)
+ return true;
+
+ /*
+ Make sure the document is long enough to contain the two length fields
+ (both number of elements or members, and number of bytes).
+ */
+ const size_t offset_size= large ? LARGE_OFFSET_SIZE : SMALL_OFFSET_SIZE;
+ /* The length has to be at least double offset size (header). */
+ if (len < 2 * offset_size)
+ return true;
+
+
+ /*
+ Every JSON Object or Array contains two numbers in the header:
+ - The number of elements in the Object / Array (Keys)
+ - The total number of bytes occupied by the JSON Object / Array, including
+ the two numbers in the header.
+ Depending on the Object / Array type (small / large) the numbers are stored
+ in 2 bytes or 4 bytes each.
+ */
+ const size_t element_count= read_offset_or_size(data, large);
+ const size_t bytes= read_offset_or_size(data + offset_size, large);
+
+ /* The value can't have more bytes than what's available in the buffer. */
+ if (bytes > len)
+ return true;
+
+ if (buffer->append(handle_as_object ? '{' : '['))
+ return true;
+
+
+ for (size_t i= 0; i < element_count; i++)
+ {
+ if (handle_as_object)
+ {
+ /*
+ The JSON Object is stored as a header part and a data part.
+ Header consists of:
+ - two length fields,
+ - an array of pointers to keys.
+ - an array of tuples (type, pointer to values)
+ * For certain types, the pointer to values is replaced by the actual
+ value. (see type_is_stored_inline)
+ Data consists of:
+ - All Key data, in order
+ - All Value data, in order
+ */
+ const size_t key_offset= 2 * offset_size + i * key_size(large);
+ const size_t key_start= read_offset_or_size(data + key_offset, large);
+ /* The length of keys is always stored in 2 bytes (large == false) */
+ const size_t key_len= read_offset_or_size(
+ data + key_offset + offset_size, false);
+
+ const size_t value_type_offset=(2 * offset_size +
+ element_count * key_size(large) +
+ i * value_size(large));
+
+ /* First print the key. */
+ if (buffer->append('"') ||
+ append_string_json(buffer, data + key_start, key_len) ||
+ buffer->append("\": "))
+ {
+ return true;
+ }
+
+ /* Then print the value. */
+ if (parse_mysql_scalar_or_value(buffer, data, bytes, value_type_offset,
+ large, depth))
+ return true;
+ }
+ else
+ {
+ /*
+ Arrays do not have the keys vector and its associated data.
+ We jump straight to reading values.
+ */
+ const size_t value_type_offset= 2 * offset_size + value_size(large) * i;
+
+ if (parse_mysql_scalar_or_value(buffer, data, bytes, value_type_offset,
+ large, depth))
+ return true;
+ }
+
+ if (i != element_count - 1 && buffer->append(", "))
+ return true;
+ }
+
+ return buffer->append(handle_as_object ? '}' : ']');
+}
+
+/**
+ Check the first byte of data which is the enum structure and based on it
+ perform parsing of object or array where each can have small or large
+ representation.
+
+ @param[out] buffer Where to print the results.
+ @param[in] type Type of value {object, array, scalar}.
+ @param[in] data Raw data for parsing.
+ @param[in] length Length of data.
+ @param[in] depth Depth size.
+*/
+bool parse_mysql_json_value(String *buffer, JSONB_TYPES type, const uchar *data,
+ size_t len, size_t depth)
+{
+ const bool IS_OBJECT=true, IS_LARGE=true;
+ switch (type) {
+ case JSONB_TYPE_SMALL_OBJECT:
+ return parse_array_or_object(buffer, data, len, IS_OBJECT, !IS_LARGE, depth);
+ case JSONB_TYPE_LARGE_OBJECT:
+ return parse_array_or_object(buffer, data, len, IS_OBJECT, IS_LARGE, depth);
+ case JSONB_TYPE_SMALL_ARRAY:
+ return parse_array_or_object(buffer, data, len, !IS_OBJECT, !IS_LARGE, depth);
+ case JSONB_TYPE_LARGE_ARRAY:
+ return parse_array_or_object(buffer, data, len, !IS_OBJECT, IS_LARGE, depth);
+ default:
+ return parse_mysql_scalar(buffer, type, data, len);
+ }
+}
diff --git a/plugin/type_mysql_json/mysql_json.h b/plugin/type_mysql_json/mysql_json.h
new file mode 100644
index 00000000..afbacafc
--- /dev/null
+++ b/plugin/type_mysql_json/mysql_json.h
@@ -0,0 +1,45 @@
+/*
+ Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2020 MariaDB Foundation
+
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#ifndef MYSQL_JSON_INCLUDED
+#define MYSQL_JSON_INCLUDED
+
+#include "my_global.h"
+#include "sql_string.h" // String
+
+enum JSONB_TYPES {
+ JSONB_TYPE_SMALL_OBJECT= 0x0,
+ JSONB_TYPE_LARGE_OBJECT= 0x1,
+ JSONB_TYPE_SMALL_ARRAY= 0x2,
+ JSONB_TYPE_LARGE_ARRAY= 0x3,
+ JSONB_TYPE_LITERAL= 0x4,
+ JSONB_TYPE_INT16= 0x5,
+ JSONB_TYPE_UINT16= 0x6,
+ JSONB_TYPE_INT32= 0x7,
+ JSONB_TYPE_UINT32= 0x8,
+ JSONB_TYPE_INT64= 0x9,
+ JSONB_TYPE_UINT64= 0xA,
+ JSONB_TYPE_DOUBLE= 0xB,
+ JSONB_TYPE_STRING= 0xC,
+ JSONB_TYPE_OPAQUE= 0xF
+};
+
+bool parse_mysql_json_value(String *buffer, JSONB_TYPES type, const uchar *data,
+ size_t len, size_t depth);
+
+#endif /* MYSQL_JSON_INCLUDED */
diff --git a/plugin/type_mysql_json/type.cc b/plugin/type_mysql_json/type.cc
new file mode 100644
index 00000000..61507a24
--- /dev/null
+++ b/plugin/type_mysql_json/type.cc
@@ -0,0 +1,216 @@
+/*
+ Copyright (c) 2020 MariaDB Foundation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include <mysql/plugin_data_type.h>
+#include <my_global.h>
+#include <sql_type.h>
+#include <field.h>
+#include <mysqld_error.h>
+#include "mysql_json.h"
+
+const LEX_CSTRING empty_clex_str= {"", 0};
+
+class Type_handler_mysql_json: public Type_handler_blob
+{
+public:
+ Field *make_conversion_table_field(MEM_ROOT *, TABLE *, uint, const Field *)
+ const override;
+ const Type_collection *type_collection() const override;
+ Field *make_table_field_from_def(TABLE_SHARE *, MEM_ROOT *,
+ const LEX_CSTRING *, const Record_addr &,
+ const Bit_addr &,
+ const Column_definition_attributes *,
+ uint32) const override;
+ Field *make_table_field(MEM_ROOT *, const LEX_CSTRING *,
+ const Record_addr &, const Type_all_attributes &,
+ TABLE_SHARE *) const override;
+ void Column_definition_reuse_fix_attributes(THD *thd,
+ Column_definition *def,
+ const Field *field) const override;
+};
+
+Type_handler_mysql_json type_handler_mysql_json;
+
+
+class Field_mysql_json: public Field_blob
+{
+public:
+ Field_mysql_json(uchar *ptr_arg, uchar *null_ptr_arg,
+ uchar null_bit_arg, enum utype unireg_check_arg,
+ const LEX_CSTRING *field_name_arg, TABLE_SHARE *share,
+ uint blob_pack_length, const DTCollation &collation)
+ : Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
+ field_name_arg, share, blob_pack_length,
+ &my_charset_utf8mb4_bin)
+ {}
+
+ String *val_str(String *val_buffer, String *val_str);
+ const Type_handler *type_handler() const { return &type_handler_mysql_json; }
+ bool parse_mysql(String *dest, const char *data, size_t length) const;
+ bool send(Protocol *protocol) { return Field::send(protocol); }
+ void sql_type(String &s) const
+ { s.set_ascii(STRING_WITH_LEN("json /* MySQL 5.7 */")); }
+ /* this will make ALTER TABLE to consider it different from built-in field */
+ Compression_method *compression_method() const { return (Compression_method*)1; }
+};
+
+Field *Type_handler_mysql_json::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata, const Field *target) const
+{
+ uint pack_length= metadata & 0x00ff;
+ if (pack_length < 1 || pack_length > 4)
+ return NULL; // Broken binary log?
+ return new (root)
+ Field_mysql_json(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str,
+ table->s, pack_length, target->charset());
+}
+
+Field *Type_handler_mysql_json::make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *root, const LEX_CSTRING *name,
+ const Record_addr &addr, const Bit_addr &bit,
+ const Column_definition_attributes *attr, uint32 flags) const
+{
+ return new (root) Field_mysql_json(addr.ptr(), addr.null_ptr(),
+ addr.null_bit(), attr->unireg_check, name, share,
+ attr->pack_flag_to_pack_length(), attr->charset);
+}
+
+void Type_handler_mysql_json::
+ Column_definition_reuse_fix_attributes(THD *thd,
+ Column_definition *def,
+ const Field *field) const
+{
+ Type_handler_blob::Column_definition_reuse_fix_attributes(thd, def, field);
+ def->decimals= 0;
+}
+
+
+
+Field *Type_handler_mysql_json::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name, const Record_addr &addr,
+ const Type_all_attributes &attr, TABLE_SHARE *share) const
+{
+ return new (root) Field_mysql_json(addr.ptr(), addr.null_ptr(),
+ addr.null_bit(), Field::NONE, name, share, 2, attr.collation);
+}
+
+
+String *Field_mysql_json::val_str(String *val_buffer, String *val_ptr)
+{
+ String *raw_value= Field_blob::val_str(val_buffer, val_ptr);
+ String data;
+
+ data.copy(*raw_value);
+
+ val_ptr->length(0);
+ if (parse_mysql(val_ptr, data.ptr(), data.length()))
+ {
+ val_ptr->length(0);
+ my_printf_error(ER_UNKNOWN_ERROR,
+ "Error parsing MySQL JSON format, please dump this table from MySQL "
+ "and then restore it to be able to use it in MariaDB.", MYF(0));
+ }
+ return val_ptr;
+}
+
+bool Field_mysql_json::parse_mysql(String *dest,
+ const char *data, size_t length) const
+{
+ if (!data)
+ return false;
+
+ /* Each JSON blob must start with a type specifier. */
+ if (length < 2)
+ return true;
+
+ if (parse_mysql_json_value(dest, static_cast<JSONB_TYPES>(data[0]),
+ reinterpret_cast<const uchar*>(data) + 1,
+ length - 1, 0))
+ return true;
+
+ return false;
+}
+
+class Type_collection_mysql_json: public Type_collection
+{
+public:
+ const Type_handler *aggregate_for_result(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ if (a == b)
+ return a;
+ return NULL;
+ }
+
+ const Type_handler *aggregate_for_min_max(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ return aggregate_for_result(a, b);
+ }
+
+ const Type_handler *aggregate_for_comparison(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ return aggregate_for_result(a, b);
+ }
+
+ const Type_handler *aggregate_for_num_op(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ return NULL;
+ }
+
+ const Type_handler *handler_by_name(const LEX_CSTRING &name) const override
+ {
+ if (type_handler_mysql_json.name().eq(name))
+ return &type_handler_mysql_json;
+ return NULL;
+ }
+};
+
+const Type_collection *Type_handler_mysql_json::type_collection() const
+{
+ static Type_collection_mysql_json type_collection_mysql_json;
+ return &type_collection_mysql_json;
+}
+
+static struct st_mariadb_data_type plugin_descriptor_type_mysql_json=
+{
+ MariaDB_DATA_TYPE_INTERFACE_VERSION,
+ &type_handler_mysql_json
+};
+
+maria_declare_plugin(type_mysql_json)
+{
+ MariaDB_DATA_TYPE_PLUGIN,
+ &plugin_descriptor_type_mysql_json,
+ "MYSQL_JSON",
+ "Anel Husaković, Vicențiu Ciorbaru",
+ "Data type MYSQL_JSON",
+ PLUGIN_LICENSE_GPL,
+ 0,
+ 0,
+ 0x0001,
+ NULL,
+ NULL,
+ "0.1",
+ MariaDB_PLUGIN_MATURITY_ALPHA
+}
+maria_declare_plugin_end;
diff --git a/plugin/type_test/CMakeLists.txt b/plugin/type_test/CMakeLists.txt
new file mode 100644
index 00000000..132458cb
--- /dev/null
+++ b/plugin/type_test/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (c) 2019, MariaDB corporation
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+MYSQL_ADD_PLUGIN(type_test plugin.cc RECOMPILE_FOR_EMBEDDED
+ MODULE_ONLY COMPONENT Test)
diff --git a/plugin/type_test/mysql-test/type_test/suite.opt b/plugin/type_test/mysql-test/type_test/suite.opt
new file mode 100644
index 00000000..edf6d838
--- /dev/null
+++ b/plugin/type_test/mysql-test/type_test/suite.opt
@@ -0,0 +1 @@
+--plugin-load-add=$TYPE_TEST_SO
diff --git a/plugin/type_test/mysql-test/type_test/suite.pm b/plugin/type_test/mysql-test/type_test/suite.pm
new file mode 100644
index 00000000..fe38ca57
--- /dev/null
+++ b/plugin/type_test/mysql-test/type_test/suite.pm
@@ -0,0 +1,10 @@
+package My::Suite::Type_test;
+
+@ISA = qw(My::Suite);
+
+return "No TYPE_TEST plugin" unless $ENV{TYPE_TEST_SO};
+
+sub is_default { 1 }
+
+bless { };
+
diff --git a/plugin/type_test/mysql-test/type_test/type_test_double-debug.result b/plugin/type_test/mysql-test/type_test/type_test_double-debug.result
new file mode 100644
index 00000000..975decca
--- /dev/null
+++ b/plugin/type_test/mysql-test/type_test/type_test_double-debug.result
@@ -0,0 +1,35 @@
+#
+# MDEV-20016 Add MariaDB_DATA_TYPE_PLUGIN
+#
+# Testing that a user-defined handler is resolved by name
+# when opening a FRM file.
+SET @old_debug_dbug=@@debug_dbug;
+SET @@debug_dbug="+d,frm_data_type_info";
+CREATE TABLE t1 (a TEST_DOUBLE);
+Warnings:
+Note 1105 build_frm_image: Field data type info length: 13
+Note 1105 DBUG: [0] name='a' type_info='test_double'
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` test_double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+Warnings:
+Note 1105 DBUG: [0] name='a' type_info='test_double'
+DROP TABLE t1;
+SET @@debug_dbug=@old_debug_dbug;
+# Testing what happens on failure to resolve a type handler by name
+SET @old_debug_dbug=@@debug_dbug;
+SET @@debug_dbug="+d,frm_data_type_info";
+CREATE TABLE t1 (a TEST_DOUBLE);
+Warnings:
+Note 1105 build_frm_image: Field data type info length: 13
+Note 1105 DBUG: [0] name='a' type_info='test_double'
+FLUSH TABLES;
+SET @@debug_dbug="+d,emulate_handler_by_name_or_error_failure";
+SHOW CREATE TABLE t1;
+ERROR HY000: Unknown data type: 'test_double'
+SELECT * FROM t1;
+ERROR HY000: Unknown data type: 'test_double'
+DROP TABLE t1;
+SET @@debug_dbug=@old_debug_dbug;
diff --git a/plugin/type_test/mysql-test/type_test/type_test_double-debug.test b/plugin/type_test/mysql-test/type_test/type_test_double-debug.test
new file mode 100644
index 00000000..ee5cf430
--- /dev/null
+++ b/plugin/type_test/mysql-test/type_test/type_test_double-debug.test
@@ -0,0 +1,32 @@
+--source include/have_debug.inc
+
+--echo #
+--echo # MDEV-20016 Add MariaDB_DATA_TYPE_PLUGIN
+--echo #
+
+--echo # Testing that a user-defined handler is resolved by name
+--echo # when opening a FRM file.
+
+SET @old_debug_dbug=@@debug_dbug;
+SET @@debug_dbug="+d,frm_data_type_info";
+CREATE TABLE t1 (a TEST_DOUBLE);
+--enable_prepare_warnings
+SHOW CREATE TABLE t1;
+--disable_prepare_warnings
+DROP TABLE t1;
+SET @@debug_dbug=@old_debug_dbug;
+
+
+--echo # Testing what happens on failure to resolve a type handler by name
+
+SET @old_debug_dbug=@@debug_dbug;
+SET @@debug_dbug="+d,frm_data_type_info";
+CREATE TABLE t1 (a TEST_DOUBLE);
+FLUSH TABLES;
+SET @@debug_dbug="+d,emulate_handler_by_name_or_error_failure";
+--error ER_UNKNOWN_DATA_TYPE
+SHOW CREATE TABLE t1;
+--error ER_UNKNOWN_DATA_TYPE
+SELECT * FROM t1;
+DROP TABLE t1;
+SET @@debug_dbug=@old_debug_dbug;
diff --git a/plugin/type_test/mysql-test/type_test/type_test_double.result b/plugin/type_test/mysql-test/type_test/type_test_double.result
new file mode 100644
index 00000000..19ebb6cd
--- /dev/null
+++ b/plugin/type_test/mysql-test/type_test/type_test_double.result
@@ -0,0 +1,704 @@
+#
+# MDEV-20016 Add MariaDB_DATA_TYPE_PLUGIN
+#
+SELECT
+PLUGIN_NAME,
+PLUGIN_VERSION,
+PLUGIN_STATUS,
+PLUGIN_TYPE,
+PLUGIN_AUTHOR,
+PLUGIN_DESCRIPTION,
+PLUGIN_LICENSE,
+PLUGIN_MATURITY,
+PLUGIN_AUTH_VERSION
+FROM INFORMATION_SCHEMA.PLUGINS
+WHERE PLUGIN_TYPE='DATA TYPE'
+ AND PLUGIN_NAME='test_double';
+PLUGIN_NAME test_double
+PLUGIN_VERSION 1.0
+PLUGIN_STATUS ACTIVE
+PLUGIN_TYPE DATA TYPE
+PLUGIN_AUTHOR MariaDB Corporation
+PLUGIN_DESCRIPTION Data type TEST_DOUBLE
+PLUGIN_LICENSE GPL
+PLUGIN_MATURITY Experimental
+PLUGIN_AUTH_VERSION 1.0
+CREATE TABLE t1 (a TEST_DOUBLE);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` test_double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1 (a TEST_DOUBLE(4));
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` test_double(4,0) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1 (a TEST_DOUBLE(10));
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` test_double(10,0) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1 (a TEST_DOUBLE(20));
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` test_double(20,0) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1 (a TEST_DOUBLE(4,2));
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` test_double(4,2) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1 (a TEST_DOUBLE(10,5));
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` test_double(10,5) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1 (a TEST_DOUBLE(20,10));
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` test_double(20,10) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+SELECT CAST('100' AS TEST_DOUBLE) AS cast;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def cast 5 22 3 Y 32896 31 63
+cast
+100
+BEGIN NOT ATOMIC
+DECLARE a TEST_DOUBLE DEFAULT 256;
+SELECT HEX(a), a;
+END;
+$$
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def HEX(a) 253 44 3 Y 0 0 8
+def a a 5 22 3 Y 32768 31 63
+HEX(a) a
+100 256
+CREATE FUNCTION f1(p TEST_DOUBLE) RETURNS TEST_DOUBLE RETURN 1;
+SHOW CREATE FUNCTION f1;
+Function sql_mode Create Function character_set_client collation_connection Database Collation
+f1 STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION CREATE DEFINER=`root`@`localhost` FUNCTION `f1`(p TEST_DOUBLE) RETURNS test_double
+RETURN 1 latin1 latin1_swedish_ci latin1_swedish_ci
+SELECT f1(10);
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def f1(10) f1(10) 5 22 1 Y 32768 31 63
+f1(10)
+1
+DROP FUNCTION f1;
+CREATE TABLE t1 (a TEST_DOUBLE);
+CREATE TABLE t2 AS SELECT a FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` test_double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (a TEST_DOUBLE);
+CREATE TABLE t2 AS SELECT COALESCE(a,a) FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `COALESCE(a,a)` test_double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (a TEST_DOUBLE);
+CREATE TABLE t2 AS SELECT LEAST(a,a) FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `LEAST(a,a)` test_double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (a TEST_DOUBLE);
+INSERT INTO t1 VALUES (1),(2);
+CREATE TABLE t2 AS SELECT MIN(a), MAX(a) FROM t1;
+SELECT * FROM t2;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def test t2 t2 MIN(a) MIN(a) 5 22 1 Y 32768 31 63
+def test t2 t2 MAX(a) MAX(a) 5 22 1 Y 32768 31 63
+MIN(a) MAX(a)
+1 2
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `MIN(a)` test_double DEFAULT NULL,
+ `MAX(a)` test_double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (id INT, a TEST_DOUBLE);
+INSERT INTO t1 VALUES (1,1),(1,2),(2,1),(2,2);
+CREATE TABLE t2 AS SELECT id, MIN(a), MAX(a) FROM t1 GROUP BY id;
+SELECT * FROM t2;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def test t2 t2 id id 3 11 1 Y 32768 0 63
+def test t2 t2 MIN(a) MIN(a) 5 22 1 Y 32768 31 63
+def test t2 t2 MAX(a) MAX(a) 5 22 1 Y 32768 31 63
+id MIN(a) MAX(a)
+1 1 2
+2 1 2
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `id` int(11) DEFAULT NULL,
+ `MIN(a)` test_double DEFAULT NULL,
+ `MAX(a)` test_double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (a TEST_DOUBLE);
+INSERT INTO t1 VALUES (1),(2);
+CREATE TABLE t2 AS SELECT DISTINCT a FROM t1;
+SELECT * FROM t2;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def test t2 t2 a a 5 22 1 Y 32768 31 63
+a
+1
+2
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` test_double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (a TEST_DOUBLE);
+INSERT INTO t1 VALUES (1);
+CREATE TABLE t2 AS SELECT (SELECT a FROM t1) AS c1;
+SELECT * FROM t2;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def test t2 t2 c1 c1 5 22 1 Y 32768 31 63
+c1
+1
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c1` test_double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (a TEST_DOUBLE);
+CREATE TABLE t2 AS SELECT a FROM t1 UNION SELECT a FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` test_double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+# Testing CREATE..LIKE
+CREATE TABLE t1 (a TEST_DOUBLE);
+CREATE TABLE t2 LIKE t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` test_double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+# Testing CREATE..SELECT
+CREATE TABLE t1 (a TEST_DOUBLE);
+CREATE TABLE t2 AS SELECT * FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` test_double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+# Testing ALTER
+CREATE TABLE t1 (a TEST_DOUBLE);
+INSERT INTO t1 VALUES (10),(20);
+SELECT * FROM t1;
+a
+10
+20
+ALTER TABLE t1 MODIFY a INT;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM t1;
+a
+10
+20
+ALTER TABLE t1 MODIFY a TEST_DOUBLE;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` test_double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM t1;
+a
+10
+20
+DROP TABLE t1;
+CREATE TABLE t1 (a TEST_DOUBLE);
+INSERT INTO t1 VALUES (10),(20);
+ALTER TABLE t1 ADD b TEST_DOUBLE DEFAULT 0;
+SELECT * FROM t1;
+a b
+10 0
+20 0
+DROP TABLE t1;
+# Testing metadata views
+CREATE TABLE t1 (a TEST_DOUBLE);
+SELECT
+TABLE_CATALOG,
+TABLE_SCHEMA,
+TABLE_NAME,
+COLUMN_NAME,
+ORDINAL_POSITION,
+COLUMN_DEFAULT,
+IS_NULLABLE,
+DATA_TYPE,
+CHARACTER_MAXIMUM_LENGTH,
+CHARACTER_OCTET_LENGTH,
+NUMERIC_PRECISION,
+NUMERIC_SCALE,
+DATETIME_PRECISION,
+CHARACTER_SET_NAME,
+COLLATION_NAME,
+COLUMN_TYPE,
+EXTRA
+FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='test';
+TABLE_CATALOG def
+TABLE_SCHEMA test
+TABLE_NAME t1
+COLUMN_NAME a
+ORDINAL_POSITION 1
+COLUMN_DEFAULT NULL
+IS_NULLABLE YES
+DATA_TYPE test_double
+CHARACTER_MAXIMUM_LENGTH NULL
+CHARACTER_OCTET_LENGTH NULL
+NUMERIC_PRECISION 22
+NUMERIC_SCALE 31
+DATETIME_PRECISION NULL
+CHARACTER_SET_NAME NULL
+COLLATION_NAME NULL
+COLUMN_TYPE test_double
+EXTRA
+SHOW COLUMNS FROM t1;
+Field Type Null Key Default Extra
+a test_double YES NULL
+DROP TABLE t1;
+# Testing indexing
+CREATE TABLE t1 (a TEST_DOUBLE, KEY(a));
+INSERT INTO t1 VALUES (0),(1),(2),(3),(4),(5),(6),(7);
+EXPLAIN SELECT * FROM t1 WHERE a=3;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref a a 9 const 1 Using index
+DROP TABLE t1;
+# Testing aggregation for result
+CREATE TABLE t1 (a TEST_DOUBLE);
+INSERT INTO t1 VALUES (0),(1),(2),(3),(4),(5),(6),(7);
+CREATE TABLE t2 AS SELECT
+COALESCE(a,1) AS c1,
+COALESCE(a,1.0) AS c2,
+COALESCE(a,1e0) AS c3
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c1` test_double DEFAULT NULL,
+ `c2` test_double DEFAULT NULL,
+ `c3` test_double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM t2 ORDER BY c1;
+c1 c2 c3
+0 0 0
+1 1 1
+2 2 2
+3 3 3
+4 4 4
+5 5 5
+6 6 6
+7 7 7
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (
+c TEST_DOUBLE,
+c_tinyint TINYINT,
+c_smallint SMALLINT,
+c_mediumint MEDIUMINT,
+c_int INT,
+c_bigint BIGINT
+);
+CREATE TABLE t2 AS SELECT
+COALESCE(c,c_tinyint),
+COALESCE(c,c_smallint),
+COALESCE(c,c_mediumint),
+COALESCE(c,c_bigint)
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `COALESCE(c,c_tinyint)` test_double DEFAULT NULL,
+ `COALESCE(c,c_smallint)` test_double DEFAULT NULL,
+ `COALESCE(c,c_mediumint)` test_double DEFAULT NULL,
+ `COALESCE(c,c_bigint)` test_double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (
+c TEST_DOUBLE,
+c_time TIME,
+c_date DATE,
+c_datetime DATETIME,
+c_timestamp TIMESTAMP
+);
+SELECT COALESCE(c, c_time) FROM t1;
+ERROR HY000: Illegal parameter data types test_double and time for operation 'coalesce'
+SELECT COALESCE(c, c_date) FROM t1;
+ERROR HY000: Illegal parameter data types test_double and date for operation 'coalesce'
+SELECT COALESCE(c, c_datetime) FROM t1;
+ERROR HY000: Illegal parameter data types test_double and datetime for operation 'coalesce'
+SELECT COALESCE(c, c_timestamp) FROM t1;
+ERROR HY000: Illegal parameter data types test_double and timestamp for operation 'coalesce'
+DROP TABLE t1;
+CREATE TABLE t1 (
+c TEST_DOUBLE,
+c_char CHAR(32),
+c_varchar VARCHAR(32),
+c_tinytext TINYTEXT,
+c_text TEXT,
+c_mediumtext MEDIUMTEXT,
+c_longtext LONGTEXT
+);
+SELECT COALESCE(c, c_char) FROM t1;
+ERROR HY000: Illegal parameter data types test_double and char for operation 'coalesce'
+SELECT COALESCE(c, c_varchar) FROM t1;
+ERROR HY000: Illegal parameter data types test_double and varchar for operation 'coalesce'
+SELECT COALESCE(c, c_tinytext) FROM t1;
+ERROR HY000: Illegal parameter data types test_double and tinyblob for operation 'coalesce'
+SELECT COALESCE(c, c_text) FROM t1;
+ERROR HY000: Illegal parameter data types test_double and blob for operation 'coalesce'
+SELECT COALESCE(c, c_mediumtext) FROM t1;
+ERROR HY000: Illegal parameter data types test_double and mediumblob for operation 'coalesce'
+SELECT COALESCE(c, c_longtext) FROM t1;
+ERROR HY000: Illegal parameter data types test_double and longblob for operation 'coalesce'
+DROP TABLE t1;
+# Testing aggregation for min/max
+CREATE TABLE t1 (a TEST_DOUBLE);
+INSERT INTO t1 VALUES (0),(1),(2),(3),(4),(5),(6),(7);
+CREATE TABLE t2 AS SELECT
+LEAST(a,1) AS c1,
+LEAST(a,1.0) AS c2,
+LEAST(a,1e0) AS c3
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c1` test_double DEFAULT NULL,
+ `c2` test_double DEFAULT NULL,
+ `c3` test_double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM t2 ORDER BY c1;
+c1 c2 c3
+0 0 0
+1 1 1
+1 1 1
+1 1 1
+1 1 1
+1 1 1
+1 1 1
+1 1 1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (
+c TEST_DOUBLE,
+c_tinyint TINYINT,
+c_smallint SMALLINT,
+c_mediumint MEDIUMINT,
+c_int INT,
+c_bigint BIGINT
+);
+CREATE TABLE t2 AS SELECT
+LEAST(c,c_tinyint),
+LEAST(c,c_smallint),
+LEAST(c,c_mediumint),
+LEAST(c,c_bigint)
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `LEAST(c,c_tinyint)` test_double DEFAULT NULL,
+ `LEAST(c,c_smallint)` test_double DEFAULT NULL,
+ `LEAST(c,c_mediumint)` test_double DEFAULT NULL,
+ `LEAST(c,c_bigint)` test_double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (
+c TEST_DOUBLE,
+c_time TIME,
+c_date DATE,
+c_datetime DATETIME,
+c_timestamp TIMESTAMP
+);
+SELECT LEAST(c, c_time) FROM t1;
+ERROR HY000: Illegal parameter data types test_double and time for operation 'least'
+SELECT LEAST(c, c_date) FROM t1;
+ERROR HY000: Illegal parameter data types test_double and date for operation 'least'
+SELECT LEAST(c, c_datetime) FROM t1;
+ERROR HY000: Illegal parameter data types test_double and datetime for operation 'least'
+SELECT LEAST(c, c_timestamp) FROM t1;
+ERROR HY000: Illegal parameter data types test_double and timestamp for operation 'least'
+DROP TABLE t1;
+CREATE TABLE t1 (
+c TEST_DOUBLE,
+c_char CHAR(32),
+c_varchar VARCHAR(32),
+c_tinytext TINYTEXT,
+c_text TEXT,
+c_mediumtext MEDIUMTEXT,
+c_longtext LONGTEXT
+);
+SELECT LEAST(c, c_char) FROM t1;
+ERROR HY000: Illegal parameter data types test_double and char for operation 'least'
+SELECT LEAST(c, c_varchar) FROM t1;
+ERROR HY000: Illegal parameter data types test_double and varchar for operation 'least'
+SELECT LEAST(c, c_tinytext) FROM t1;
+ERROR HY000: Illegal parameter data types test_double and tinyblob for operation 'least'
+SELECT LEAST(c, c_text) FROM t1;
+ERROR HY000: Illegal parameter data types test_double and blob for operation 'least'
+SELECT LEAST(c, c_mediumtext) FROM t1;
+ERROR HY000: Illegal parameter data types test_double and mediumblob for operation 'least'
+SELECT LEAST(c, c_longtext) FROM t1;
+ERROR HY000: Illegal parameter data types test_double and longblob for operation 'least'
+DROP TABLE t1;
+# Testing aggregation for numeric operation - plus
+CREATE TABLE t1 (a TEST_DOUBLE);
+INSERT INTO t1 VALUES (0),(1),(2),(3),(4),(5),(6),(7);
+CREATE TABLE t2 AS SELECT
+a+1 AS c1,
+a+1.0 AS c2,
+a+1e0 AS c3
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c1` test_double DEFAULT NULL,
+ `c2` test_double DEFAULT NULL,
+ `c3` test_double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM t2 ORDER BY c1;
+c1 c2 c3
+1 1 1
+2 2 2
+3 3 3
+4 4 4
+5 5 5
+6 6 6
+7 7 7
+8 8 8
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (
+c TEST_DOUBLE,
+c_tinyint TINYINT,
+c_smallint SMALLINT,
+c_mediumint MEDIUMINT,
+c_int INT,
+c_bigint BIGINT
+);
+CREATE TABLE t2 AS SELECT
+c + c_tinyint,
+c + c_smallint,
+c + c_mediumint,
+c + c_bigint
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c + c_tinyint` test_double DEFAULT NULL,
+ `c + c_smallint` test_double DEFAULT NULL,
+ `c + c_mediumint` test_double DEFAULT NULL,
+ `c + c_bigint` test_double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (
+c TEST_DOUBLE,
+c_time TIME,
+c_date DATE,
+c_datetime DATETIME,
+c_timestamp TIMESTAMP
+);
+SELECT c + c_time FROM t1;
+ERROR HY000: Illegal parameter data types test_double and time for operation '+'
+SELECT c + c_date FROM t1;
+ERROR HY000: Illegal parameter data types test_double and date for operation '+'
+SELECT c + c_datetime FROM t1;
+ERROR HY000: Illegal parameter data types test_double and datetime for operation '+'
+SELECT c + c_timestamp FROM t1;
+ERROR HY000: Illegal parameter data types test_double and timestamp for operation '+'
+DROP TABLE t1;
+CREATE TABLE t1 (
+c TEST_DOUBLE,
+c_char CHAR(32),
+c_varchar VARCHAR(32),
+c_tinytext TINYTEXT,
+c_text TEXT,
+c_mediumtext MEDIUMTEXT,
+c_longtext LONGTEXT
+);
+SELECT c + c_char FROM t1;
+ERROR HY000: Illegal parameter data types test_double and char for operation '+'
+SELECT c + c_varchar FROM t1;
+ERROR HY000: Illegal parameter data types test_double and varchar for operation '+'
+SELECT c + c_tinytext FROM t1;
+ERROR HY000: Illegal parameter data types test_double and tinyblob for operation '+'
+SELECT c + c_text FROM t1;
+ERROR HY000: Illegal parameter data types test_double and blob for operation '+'
+SELECT c + c_mediumtext FROM t1;
+ERROR HY000: Illegal parameter data types test_double and mediumblob for operation '+'
+SELECT c + c_longtext FROM t1;
+ERROR HY000: Illegal parameter data types test_double and longblob for operation '+'
+DROP TABLE t1;
+# Testing aggregation for numeric operation - minus
+CREATE TABLE t1 (a TEST_DOUBLE);
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8);
+CREATE TABLE t2 AS SELECT
+a-1 AS c1,
+a-1.0 AS c2,
+a-1e0 AS c3
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c1` test_double DEFAULT NULL,
+ `c2` test_double DEFAULT NULL,
+ `c3` test_double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM t2 ORDER BY c1;
+c1 c2 c3
+0 0 0
+1 1 1
+2 2 2
+3 3 3
+4 4 4
+5 5 5
+6 6 6
+7 7 7
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (
+c TEST_DOUBLE,
+c_tinyint TINYINT,
+c_smallint SMALLINT,
+c_mediumint MEDIUMINT,
+c_int INT,
+c_bigint BIGINT
+);
+CREATE TABLE t2 AS SELECT
+c - c_tinyint,
+c - c_smallint,
+c - c_mediumint,
+c - c_bigint
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c - c_tinyint` test_double DEFAULT NULL,
+ `c - c_smallint` test_double DEFAULT NULL,
+ `c - c_mediumint` test_double DEFAULT NULL,
+ `c - c_bigint` test_double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (
+c TEST_DOUBLE,
+c_time TIME,
+c_date DATE,
+c_datetime DATETIME,
+c_timestamp TIMESTAMP
+);
+SELECT c - c_time FROM t1;
+ERROR HY000: Illegal parameter data types test_double and time for operation '-'
+SELECT c - c_date FROM t1;
+ERROR HY000: Illegal parameter data types test_double and date for operation '-'
+SELECT c - c_datetime FROM t1;
+ERROR HY000: Illegal parameter data types test_double and datetime for operation '-'
+SELECT c - c_timestamp FROM t1;
+ERROR HY000: Illegal parameter data types test_double and timestamp for operation '-'
+DROP TABLE t1;
+CREATE TABLE t1 (
+c TEST_DOUBLE,
+c_char CHAR(32),
+c_varchar VARCHAR(32),
+c_tinytext TINYTEXT,
+c_text TEXT,
+c_mediumtext MEDIUMTEXT,
+c_longtext LONGTEXT
+);
+SELECT c - c_char FROM t1;
+ERROR HY000: Illegal parameter data types test_double and char for operation '-'
+SELECT c - c_varchar FROM t1;
+ERROR HY000: Illegal parameter data types test_double and varchar for operation '-'
+SELECT c - c_tinytext FROM t1;
+ERROR HY000: Illegal parameter data types test_double and tinyblob for operation '-'
+SELECT c - c_text FROM t1;
+ERROR HY000: Illegal parameter data types test_double and blob for operation '-'
+SELECT c - c_mediumtext FROM t1;
+ERROR HY000: Illegal parameter data types test_double and mediumblob for operation '-'
+SELECT c - c_longtext FROM t1;
+ERROR HY000: Illegal parameter data types test_double and longblob for operation '-'
+DROP TABLE t1;
+# Testing CAST to other data types
+CREATE TABLE t1 (a TEST_DOUBLE);
+INSERT INTO t1 VALUES (20000102);
+CREATE TABLE t2 AS SELECT
+a,
+CAST(a AS CHAR),
+CAST(a AS DECIMAL),
+CAST(a AS DOUBLE),
+CAST(a AS SIGNED),
+CAST(a AS UNSIGNED),
+CAST(a AS TIME),
+CAST(a AS DATETIME),
+CAST(a AS DATE)
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` test_double DEFAULT NULL,
+ `CAST(a AS CHAR)` varchar(22) DEFAULT NULL,
+ `CAST(a AS DECIMAL)` decimal(10,0) DEFAULT NULL,
+ `CAST(a AS DOUBLE)` double DEFAULT NULL,
+ `CAST(a AS SIGNED)` bigint(20) DEFAULT NULL,
+ `CAST(a AS UNSIGNED)` bigint(20) unsigned DEFAULT NULL,
+ `CAST(a AS TIME)` time DEFAULT NULL,
+ `CAST(a AS DATETIME)` datetime DEFAULT NULL,
+ `CAST(a AS DATE)` date DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM t2;
+a 20000102
+CAST(a AS CHAR) 20000102
+CAST(a AS DECIMAL) 20000102
+CAST(a AS DOUBLE) 20000102
+CAST(a AS SIGNED) 20000102
+CAST(a AS UNSIGNED) 20000102
+CAST(a AS TIME) 00:00:00
+CAST(a AS DATETIME) 2000-01-02 00:00:00
+CAST(a AS DATE) 2000-01-02
+DROP TABLE t2;
+DROP TABLE t1;
diff --git a/plugin/type_test/mysql-test/type_test/type_test_double.test b/plugin/type_test/mysql-test/type_test/type_test_double.test
new file mode 100644
index 00000000..993eab95
--- /dev/null
+++ b/plugin/type_test/mysql-test/type_test/type_test_double.test
@@ -0,0 +1,530 @@
+--echo #
+--echo # MDEV-20016 Add MariaDB_DATA_TYPE_PLUGIN
+--echo #
+
+--vertical_results
+SELECT
+ PLUGIN_NAME,
+ PLUGIN_VERSION,
+ PLUGIN_STATUS,
+ PLUGIN_TYPE,
+ PLUGIN_AUTHOR,
+ PLUGIN_DESCRIPTION,
+ PLUGIN_LICENSE,
+ PLUGIN_MATURITY,
+ PLUGIN_AUTH_VERSION
+FROM INFORMATION_SCHEMA.PLUGINS
+ WHERE PLUGIN_TYPE='DATA TYPE'
+ AND PLUGIN_NAME='test_double';
+--horizontal_results
+
+CREATE TABLE t1 (a TEST_DOUBLE);
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TEST_DOUBLE(4));
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TEST_DOUBLE(10));
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TEST_DOUBLE(20));
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+
+CREATE TABLE t1 (a TEST_DOUBLE(4,2));
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TEST_DOUBLE(10,5));
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TEST_DOUBLE(20,10));
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+
+--disable_ps_protocol
+--enable_metadata
+SELECT CAST('100' AS TEST_DOUBLE) AS cast;
+--disable_metadata
+--enable_ps_protocol
+
+--disable_ps_protocol
+--enable_metadata
+DELIMITER $$;
+BEGIN NOT ATOMIC
+ DECLARE a TEST_DOUBLE DEFAULT 256;
+ SELECT HEX(a), a;
+END;
+$$
+DELIMITER ;$$
+--disable_metadata
+--enable_ps_protocol
+
+CREATE FUNCTION f1(p TEST_DOUBLE) RETURNS TEST_DOUBLE RETURN 1;
+SHOW CREATE FUNCTION f1;
+--disable_ps_protocol
+--enable_metadata
+SELECT f1(10);
+--disable_metadata
+--enable_ps_protocol
+DROP FUNCTION f1;
+
+CREATE TABLE t1 (a TEST_DOUBLE);
+CREATE TABLE t2 AS SELECT a FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TEST_DOUBLE);
+CREATE TABLE t2 AS SELECT COALESCE(a,a) FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TEST_DOUBLE);
+CREATE TABLE t2 AS SELECT LEAST(a,a) FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TEST_DOUBLE);
+INSERT INTO t1 VALUES (1),(2);
+CREATE TABLE t2 AS SELECT MIN(a), MAX(a) FROM t1;
+--disable_ps_protocol
+--enable_metadata
+SELECT * FROM t2;
+--disable_metadata
+--enable_ps_protocol
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (id INT, a TEST_DOUBLE);
+INSERT INTO t1 VALUES (1,1),(1,2),(2,1),(2,2);
+CREATE TABLE t2 AS SELECT id, MIN(a), MAX(a) FROM t1 GROUP BY id;
+--disable_ps_protocol
+--enable_metadata
+SELECT * FROM t2;
+--disable_metadata
+--enable_ps_protocol
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TEST_DOUBLE);
+INSERT INTO t1 VALUES (1),(2);
+CREATE TABLE t2 AS SELECT DISTINCT a FROM t1;
+--disable_ps_protocol
+--enable_metadata
+SELECT * FROM t2;
+--disable_metadata
+--enable_ps_protocol
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TEST_DOUBLE);
+INSERT INTO t1 VALUES (1);
+CREATE TABLE t2 AS SELECT (SELECT a FROM t1) AS c1;
+--disable_ps_protocol
+--enable_metadata
+SELECT * FROM t2;
+--disable_metadata
+--enable_ps_protocol
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TEST_DOUBLE);
+CREATE TABLE t2 AS SELECT a FROM t1 UNION SELECT a FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+--echo # Testing CREATE..LIKE
+
+CREATE TABLE t1 (a TEST_DOUBLE);
+CREATE TABLE t2 LIKE t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+--echo # Testing CREATE..SELECT
+
+CREATE TABLE t1 (a TEST_DOUBLE);
+CREATE TABLE t2 AS SELECT * FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+
+--echo # Testing ALTER
+
+CREATE TABLE t1 (a TEST_DOUBLE);
+INSERT INTO t1 VALUES (10),(20);
+SELECT * FROM t1;
+ALTER TABLE t1 MODIFY a INT;
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+ALTER TABLE t1 MODIFY a TEST_DOUBLE;
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TEST_DOUBLE);
+INSERT INTO t1 VALUES (10),(20);
+ALTER TABLE t1 ADD b TEST_DOUBLE DEFAULT 0;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo # Testing metadata views
+
+CREATE TABLE t1 (a TEST_DOUBLE);
+--vertical_results
+SELECT
+ TABLE_CATALOG,
+ TABLE_SCHEMA,
+ TABLE_NAME,
+ COLUMN_NAME,
+ ORDINAL_POSITION,
+ COLUMN_DEFAULT,
+ IS_NULLABLE,
+ DATA_TYPE,
+ CHARACTER_MAXIMUM_LENGTH,
+ CHARACTER_OCTET_LENGTH,
+ NUMERIC_PRECISION,
+ NUMERIC_SCALE,
+ DATETIME_PRECISION,
+ CHARACTER_SET_NAME,
+ COLLATION_NAME,
+ COLUMN_TYPE,
+ EXTRA
+FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='test';
+--horizontal_results
+SHOW COLUMNS FROM t1;
+DROP TABLE t1;
+
+
+--echo # Testing indexing
+
+CREATE TABLE t1 (a TEST_DOUBLE, KEY(a));
+INSERT INTO t1 VALUES (0),(1),(2),(3),(4),(5),(6),(7);
+EXPLAIN SELECT * FROM t1 WHERE a=3;
+DROP TABLE t1;
+
+--echo # Testing aggregation for result
+
+CREATE TABLE t1 (a TEST_DOUBLE);
+INSERT INTO t1 VALUES (0),(1),(2),(3),(4),(5),(6),(7);
+CREATE TABLE t2 AS SELECT
+ COALESCE(a,1) AS c1,
+ COALESCE(a,1.0) AS c2,
+ COALESCE(a,1e0) AS c3
+FROM t1;
+SHOW CREATE TABLE t2;
+SELECT * FROM t2 ORDER BY c1;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ c TEST_DOUBLE,
+ c_tinyint TINYINT,
+ c_smallint SMALLINT,
+ c_mediumint MEDIUMINT,
+ c_int INT,
+ c_bigint BIGINT
+);
+CREATE TABLE t2 AS SELECT
+ COALESCE(c,c_tinyint),
+ COALESCE(c,c_smallint),
+ COALESCE(c,c_mediumint),
+ COALESCE(c,c_bigint)
+FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ c TEST_DOUBLE,
+ c_time TIME,
+ c_date DATE,
+ c_datetime DATETIME,
+ c_timestamp TIMESTAMP
+);
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT COALESCE(c, c_time) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT COALESCE(c, c_date) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT COALESCE(c, c_datetime) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT COALESCE(c, c_timestamp) FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ c TEST_DOUBLE,
+ c_char CHAR(32),
+ c_varchar VARCHAR(32),
+ c_tinytext TINYTEXT,
+ c_text TEXT,
+ c_mediumtext MEDIUMTEXT,
+ c_longtext LONGTEXT
+);
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT COALESCE(c, c_char) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT COALESCE(c, c_varchar) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT COALESCE(c, c_tinytext) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT COALESCE(c, c_text) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT COALESCE(c, c_mediumtext) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT COALESCE(c, c_longtext) FROM t1;
+DROP TABLE t1;
+
+--echo # Testing aggregation for min/max
+
+CREATE TABLE t1 (a TEST_DOUBLE);
+INSERT INTO t1 VALUES (0),(1),(2),(3),(4),(5),(6),(7);
+CREATE TABLE t2 AS SELECT
+ LEAST(a,1) AS c1,
+ LEAST(a,1.0) AS c2,
+ LEAST(a,1e0) AS c3
+FROM t1;
+SHOW CREATE TABLE t2;
+SELECT * FROM t2 ORDER BY c1;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ c TEST_DOUBLE,
+ c_tinyint TINYINT,
+ c_smallint SMALLINT,
+ c_mediumint MEDIUMINT,
+ c_int INT,
+ c_bigint BIGINT
+);
+CREATE TABLE t2 AS SELECT
+ LEAST(c,c_tinyint),
+ LEAST(c,c_smallint),
+ LEAST(c,c_mediumint),
+ LEAST(c,c_bigint)
+FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ c TEST_DOUBLE,
+ c_time TIME,
+ c_date DATE,
+ c_datetime DATETIME,
+ c_timestamp TIMESTAMP
+);
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT LEAST(c, c_time) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT LEAST(c, c_date) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT LEAST(c, c_datetime) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT LEAST(c, c_timestamp) FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ c TEST_DOUBLE,
+ c_char CHAR(32),
+ c_varchar VARCHAR(32),
+ c_tinytext TINYTEXT,
+ c_text TEXT,
+ c_mediumtext MEDIUMTEXT,
+ c_longtext LONGTEXT
+);
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT LEAST(c, c_char) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT LEAST(c, c_varchar) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT LEAST(c, c_tinytext) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT LEAST(c, c_text) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT LEAST(c, c_mediumtext) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT LEAST(c, c_longtext) FROM t1;
+DROP TABLE t1;
+
+
+--echo # Testing aggregation for numeric operation - plus
+
+CREATE TABLE t1 (a TEST_DOUBLE);
+INSERT INTO t1 VALUES (0),(1),(2),(3),(4),(5),(6),(7);
+CREATE TABLE t2 AS SELECT
+ a+1 AS c1,
+ a+1.0 AS c2,
+ a+1e0 AS c3
+FROM t1;
+SHOW CREATE TABLE t2;
+SELECT * FROM t2 ORDER BY c1;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ c TEST_DOUBLE,
+ c_tinyint TINYINT,
+ c_smallint SMALLINT,
+ c_mediumint MEDIUMINT,
+ c_int INT,
+ c_bigint BIGINT
+);
+CREATE TABLE t2 AS SELECT
+ c + c_tinyint,
+ c + c_smallint,
+ c + c_mediumint,
+ c + c_bigint
+FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ c TEST_DOUBLE,
+ c_time TIME,
+ c_date DATE,
+ c_datetime DATETIME,
+ c_timestamp TIMESTAMP
+);
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c + c_time FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c + c_date FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c + c_datetime FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c + c_timestamp FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ c TEST_DOUBLE,
+ c_char CHAR(32),
+ c_varchar VARCHAR(32),
+ c_tinytext TINYTEXT,
+ c_text TEXT,
+ c_mediumtext MEDIUMTEXT,
+ c_longtext LONGTEXT
+);
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c + c_char FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c + c_varchar FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c + c_tinytext FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c + c_text FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c + c_mediumtext FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c + c_longtext FROM t1;
+DROP TABLE t1;
+
+--echo # Testing aggregation for numeric operation - minus
+
+CREATE TABLE t1 (a TEST_DOUBLE);
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8);
+CREATE TABLE t2 AS SELECT
+ a-1 AS c1,
+ a-1.0 AS c2,
+ a-1e0 AS c3
+FROM t1;
+SHOW CREATE TABLE t2;
+SELECT * FROM t2 ORDER BY c1;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ c TEST_DOUBLE,
+ c_tinyint TINYINT,
+ c_smallint SMALLINT,
+ c_mediumint MEDIUMINT,
+ c_int INT,
+ c_bigint BIGINT
+);
+CREATE TABLE t2 AS SELECT
+ c - c_tinyint,
+ c - c_smallint,
+ c - c_mediumint,
+ c - c_bigint
+FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ c TEST_DOUBLE,
+ c_time TIME,
+ c_date DATE,
+ c_datetime DATETIME,
+ c_timestamp TIMESTAMP
+);
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c - c_time FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c - c_date FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c - c_datetime FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c - c_timestamp FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ c TEST_DOUBLE,
+ c_char CHAR(32),
+ c_varchar VARCHAR(32),
+ c_tinytext TINYTEXT,
+ c_text TEXT,
+ c_mediumtext MEDIUMTEXT,
+ c_longtext LONGTEXT
+);
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c - c_char FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c - c_varchar FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c - c_tinytext FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c - c_text FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c - c_mediumtext FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c - c_longtext FROM t1;
+DROP TABLE t1;
+
+--echo # Testing CAST to other data types
+
+CREATE TABLE t1 (a TEST_DOUBLE);
+INSERT INTO t1 VALUES (20000102);
+CREATE TABLE t2 AS SELECT
+ a,
+ CAST(a AS CHAR),
+ CAST(a AS DECIMAL),
+ CAST(a AS DOUBLE),
+ CAST(a AS SIGNED),
+ CAST(a AS UNSIGNED),
+ CAST(a AS TIME),
+ CAST(a AS DATETIME),
+ CAST(a AS DATE)
+FROM t1;
+SHOW CREATE TABLE t2;
+--vertical_results
+SELECT * FROM t2;
+--horizontal_results
+DROP TABLE t2;
+DROP TABLE t1;
diff --git a/plugin/type_test/mysql-test/type_test/type_test_int8-debug.result b/plugin/type_test/mysql-test/type_test/type_test_int8-debug.result
new file mode 100644
index 00000000..952a63c8
--- /dev/null
+++ b/plugin/type_test/mysql-test/type_test/type_test_int8-debug.result
@@ -0,0 +1,35 @@
+#
+# MDEV-20016 Add MariaDB_DATA_TYPE_PLUGIN
+#
+# Testing that a user-defined handler is resolved by name
+# when opening a FRM file.
+SET @old_debug_dbug=@@debug_dbug;
+SET @@debug_dbug="+d,frm_data_type_info";
+CREATE TABLE t1 (a TEST_INT8);
+Warnings:
+Note 1105 build_frm_image: Field data type info length: 11
+Note 1105 DBUG: [0] name='a' type_info='test_int8'
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` test_int8(20) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+Warnings:
+Note 1105 DBUG: [0] name='a' type_info='test_int8'
+DROP TABLE t1;
+SET @@debug_dbug=@old_debug_dbug;
+# Testing what happens on failure to resolve a type handler by name
+SET @old_debug_dbug=@@debug_dbug;
+SET @@debug_dbug="+d,frm_data_type_info";
+CREATE TABLE t1 (a TEST_INT8);
+Warnings:
+Note 1105 build_frm_image: Field data type info length: 11
+Note 1105 DBUG: [0] name='a' type_info='test_int8'
+FLUSH TABLES;
+SET @@debug_dbug="+d,emulate_handler_by_name_or_error_failure";
+SHOW CREATE TABLE t1;
+ERROR HY000: Unknown data type: 'test_int8'
+SELECT * FROM t1;
+ERROR HY000: Unknown data type: 'test_int8'
+DROP TABLE t1;
+SET @@debug_dbug=@old_debug_dbug;
diff --git a/plugin/type_test/mysql-test/type_test/type_test_int8-debug.test b/plugin/type_test/mysql-test/type_test/type_test_int8-debug.test
new file mode 100644
index 00000000..7e60bf3e
--- /dev/null
+++ b/plugin/type_test/mysql-test/type_test/type_test_int8-debug.test
@@ -0,0 +1,32 @@
+--source include/have_debug.inc
+
+--echo #
+--echo # MDEV-20016 Add MariaDB_DATA_TYPE_PLUGIN
+--echo #
+
+--echo # Testing that a user-defined handler is resolved by name
+--echo # when opening a FRM file.
+
+SET @old_debug_dbug=@@debug_dbug;
+SET @@debug_dbug="+d,frm_data_type_info";
+CREATE TABLE t1 (a TEST_INT8);
+--enable_prepare_warnings
+SHOW CREATE TABLE t1;
+--disable_prepare_warnings
+DROP TABLE t1;
+SET @@debug_dbug=@old_debug_dbug;
+
+
+--echo # Testing what happens on failure to resolve a type handler by name
+
+SET @old_debug_dbug=@@debug_dbug;
+SET @@debug_dbug="+d,frm_data_type_info";
+CREATE TABLE t1 (a TEST_INT8);
+FLUSH TABLES;
+SET @@debug_dbug="+d,emulate_handler_by_name_or_error_failure";
+--error ER_UNKNOWN_DATA_TYPE
+SHOW CREATE TABLE t1;
+--error ER_UNKNOWN_DATA_TYPE
+SELECT * FROM t1;
+DROP TABLE t1;
+SET @@debug_dbug=@old_debug_dbug;
diff --git a/plugin/type_test/mysql-test/type_test/type_test_int8.result b/plugin/type_test/mysql-test/type_test/type_test_int8.result
new file mode 100644
index 00000000..f18c990c
--- /dev/null
+++ b/plugin/type_test/mysql-test/type_test/type_test_int8.result
@@ -0,0 +1,683 @@
+#
+# MDEV-20016 Add MariaDB_DATA_TYPE_PLUGIN
+#
+SELECT
+PLUGIN_NAME,
+PLUGIN_VERSION,
+PLUGIN_STATUS,
+PLUGIN_TYPE,
+PLUGIN_AUTHOR,
+PLUGIN_DESCRIPTION,
+PLUGIN_LICENSE,
+PLUGIN_MATURITY,
+PLUGIN_AUTH_VERSION
+FROM INFORMATION_SCHEMA.PLUGINS
+WHERE PLUGIN_TYPE='DATA TYPE'
+ AND PLUGIN_NAME='test_int8';
+PLUGIN_NAME test_int8
+PLUGIN_VERSION 1.0
+PLUGIN_STATUS ACTIVE
+PLUGIN_TYPE DATA TYPE
+PLUGIN_AUTHOR MariaDB Corporation
+PLUGIN_DESCRIPTION Data type TEST_INT8
+PLUGIN_LICENSE GPL
+PLUGIN_MATURITY Experimental
+PLUGIN_AUTH_VERSION 1.0
+CREATE TABLE t1 (a TEST_INT8);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` test_int8(20) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1 (a TEST_INT8(4));
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` test_int8(4) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1 (a TEST_INT8(10));
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` test_int8(10) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1 (a TEST_INT8(20));
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` test_int8(20) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t1;
+SELECT CAST('100' AS TEST_INT8) AS cast;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def cast 3 3 3 N 32897 0 63
+cast
+100
+BEGIN NOT ATOMIC
+DECLARE a TEST_INT8 DEFAULT 256;
+SELECT HEX(a), a;
+END;
+$$
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def HEX(a) 253 40 3 Y 0 0 8
+def a a 8 20 3 Y 32768 0 63
+HEX(a) a
+100 256
+CREATE FUNCTION f1(p TEST_INT8) RETURNS TEST_INT8 RETURN 1;
+SHOW CREATE FUNCTION f1;
+Function sql_mode Create Function character_set_client collation_connection Database Collation
+f1 STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION CREATE DEFINER=`root`@`localhost` FUNCTION `f1`(p TEST_INT8) RETURNS test_int8(20)
+RETURN 1 latin1 latin1_swedish_ci latin1_swedish_ci
+SELECT f1(10);
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def f1(10) f1(10) 8 20 1 Y 32768 0 63
+f1(10)
+1
+DROP FUNCTION f1;
+CREATE TABLE t1 (a TEST_INT8);
+CREATE TABLE t2 AS SELECT a FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` test_int8(20) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (a TEST_INT8);
+CREATE TABLE t2 AS SELECT COALESCE(a,a) FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `COALESCE(a,a)` test_int8(20) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (a TEST_INT8);
+CREATE TABLE t2 AS SELECT LEAST(a,a) FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `LEAST(a,a)` test_int8(20) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (a TEST_INT8);
+INSERT INTO t1 VALUES (1),(2);
+CREATE TABLE t2 AS SELECT MIN(a), MAX(a) FROM t1;
+SELECT * FROM t2;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def test t2 t2 MIN(a) MIN(a) 8 20 1 Y 32768 0 63
+def test t2 t2 MAX(a) MAX(a) 8 20 1 Y 32768 0 63
+MIN(a) MAX(a)
+1 2
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `MIN(a)` test_int8(20) DEFAULT NULL,
+ `MAX(a)` test_int8(20) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (id INT, a TEST_INT8);
+INSERT INTO t1 VALUES (1,1),(1,2),(2,1),(2,2);
+CREATE TABLE t2 AS SELECT id, MIN(a), MAX(a) FROM t1 GROUP BY id;
+SELECT * FROM t2;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def test t2 t2 id id 3 11 1 Y 32768 0 63
+def test t2 t2 MIN(a) MIN(a) 8 20 1 Y 32768 0 63
+def test t2 t2 MAX(a) MAX(a) 8 20 1 Y 32768 0 63
+id MIN(a) MAX(a)
+1 1 2
+2 1 2
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `id` int(11) DEFAULT NULL,
+ `MIN(a)` test_int8(20) DEFAULT NULL,
+ `MAX(a)` test_int8(20) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (a TEST_INT8);
+INSERT INTO t1 VALUES (1),(2);
+CREATE TABLE t2 AS SELECT DISTINCT a FROM t1;
+SELECT * FROM t2;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def test t2 t2 a a 8 20 1 Y 32768 0 63
+a
+1
+2
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` test_int8(20) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (a TEST_INT8);
+INSERT INTO t1 VALUES (1);
+CREATE TABLE t2 AS SELECT (SELECT a FROM t1) AS c1;
+SELECT * FROM t2;
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def test t2 t2 c1 c1 8 20 1 Y 32768 0 63
+c1
+1
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c1` test_int8(20) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (a TEST_INT8);
+CREATE TABLE t2 AS SELECT a FROM t1 UNION SELECT a FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` test_int8(20) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+# Testing CREATE..LIKE
+CREATE TABLE t1 (a TEST_INT8);
+CREATE TABLE t2 LIKE t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` test_int8(20) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+# Testing CREATE..SELECT
+CREATE TABLE t1 (a TEST_INT8);
+CREATE TABLE t2 AS SELECT * FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` test_int8(20) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+# Testing ALTER
+CREATE TABLE t1 (a TEST_INT8);
+INSERT INTO t1 VALUES (10),(20);
+SELECT * FROM t1;
+a
+10
+20
+ALTER TABLE t1 MODIFY a INT;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM t1;
+a
+10
+20
+ALTER TABLE t1 MODIFY a TEST_INT8;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` test_int8(20) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM t1;
+a
+10
+20
+DROP TABLE t1;
+CREATE TABLE t1 (a TEST_INT8);
+INSERT INTO t1 VALUES (10),(20);
+ALTER TABLE t1 ADD b TEST_INT8 DEFAULT 0;
+SELECT * FROM t1;
+a b
+10 0
+20 0
+DROP TABLE t1;
+# Testing metadata views
+CREATE TABLE t1 (a TEST_INT8);
+SELECT
+TABLE_CATALOG,
+TABLE_SCHEMA,
+TABLE_NAME,
+COLUMN_NAME,
+ORDINAL_POSITION,
+COLUMN_DEFAULT,
+IS_NULLABLE,
+DATA_TYPE,
+CHARACTER_MAXIMUM_LENGTH,
+CHARACTER_OCTET_LENGTH,
+NUMERIC_PRECISION,
+NUMERIC_SCALE,
+DATETIME_PRECISION,
+CHARACTER_SET_NAME,
+COLLATION_NAME,
+COLUMN_TYPE,
+EXTRA
+FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='test';
+TABLE_CATALOG def
+TABLE_SCHEMA test
+TABLE_NAME t1
+COLUMN_NAME a
+ORDINAL_POSITION 1
+COLUMN_DEFAULT NULL
+IS_NULLABLE YES
+DATA_TYPE test_int8
+CHARACTER_MAXIMUM_LENGTH NULL
+CHARACTER_OCTET_LENGTH NULL
+NUMERIC_PRECISION 19
+NUMERIC_SCALE 0
+DATETIME_PRECISION NULL
+CHARACTER_SET_NAME NULL
+COLLATION_NAME NULL
+COLUMN_TYPE test_int8(20)
+EXTRA
+SHOW COLUMNS FROM t1;
+Field Type Null Key Default Extra
+a test_int8(20) YES NULL
+DROP TABLE t1;
+# Testing indexing
+CREATE TABLE t1 (a TEST_INT8, KEY(a));
+INSERT INTO t1 VALUES (0),(1),(2),(3),(4),(5),(6),(7);
+EXPLAIN SELECT * FROM t1 WHERE a=3;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref a a 9 const 1 Using index
+DROP TABLE t1;
+# Testing aggregation for result
+CREATE TABLE t1 (a TEST_INT8);
+INSERT INTO t1 VALUES (0),(1),(2),(3),(4),(5),(6),(7);
+CREATE TABLE t2 AS SELECT
+COALESCE(a,1) AS c1,
+COALESCE(a,1.0) AS c2,
+COALESCE(a,1e0) AS c3
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c1` test_int8(20) DEFAULT NULL,
+ `c2` decimal(20,1) DEFAULT NULL,
+ `c3` double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM t2 ORDER BY c1;
+c1 c2 c3
+0 0.0 0
+1 1.0 1
+2 2.0 2
+3 3.0 3
+4 4.0 4
+5 5.0 5
+6 6.0 6
+7 7.0 7
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (
+c TEST_INT8,
+c_tinyint TINYINT,
+c_smallint SMALLINT,
+c_mediumint MEDIUMINT,
+c_int INT,
+c_bigint BIGINT
+);
+CREATE TABLE t2 AS SELECT
+COALESCE(c,c_tinyint),
+COALESCE(c,c_smallint),
+COALESCE(c,c_mediumint),
+COALESCE(c,c_bigint)
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `COALESCE(c,c_tinyint)` test_int8(20) DEFAULT NULL,
+ `COALESCE(c,c_smallint)` test_int8(20) DEFAULT NULL,
+ `COALESCE(c,c_mediumint)` test_int8(20) DEFAULT NULL,
+ `COALESCE(c,c_bigint)` test_int8(20) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (
+c TEST_INT8,
+c_time TIME,
+c_date DATE,
+c_datetime DATETIME,
+c_timestamp TIMESTAMP
+);
+SELECT COALESCE(c, c_time) FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and time for operation 'coalesce'
+SELECT COALESCE(c, c_date) FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and date for operation 'coalesce'
+SELECT COALESCE(c, c_datetime) FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and datetime for operation 'coalesce'
+SELECT COALESCE(c, c_timestamp) FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and timestamp for operation 'coalesce'
+DROP TABLE t1;
+CREATE TABLE t1 (
+c TEST_INT8,
+c_char CHAR(32),
+c_varchar VARCHAR(32),
+c_tinytext TINYTEXT,
+c_text TEXT,
+c_mediumtext MEDIUMTEXT,
+c_longtext LONGTEXT
+);
+SELECT COALESCE(c, c_char) FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and char for operation 'coalesce'
+SELECT COALESCE(c, c_varchar) FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and varchar for operation 'coalesce'
+SELECT COALESCE(c, c_tinytext) FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and tinyblob for operation 'coalesce'
+SELECT COALESCE(c, c_text) FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and blob for operation 'coalesce'
+SELECT COALESCE(c, c_mediumtext) FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and mediumblob for operation 'coalesce'
+SELECT COALESCE(c, c_longtext) FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and longblob for operation 'coalesce'
+DROP TABLE t1;
+# Testing aggregation for min/max
+CREATE TABLE t1 (a TEST_INT8);
+INSERT INTO t1 VALUES (0),(1),(2),(3),(4),(5),(6),(7);
+CREATE TABLE t2 AS SELECT
+LEAST(a,1) AS c1,
+LEAST(a,1.0) AS c2,
+LEAST(a,1e0) AS c3
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c1` test_int8(20) DEFAULT NULL,
+ `c2` decimal(20,1) DEFAULT NULL,
+ `c3` double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM t2 ORDER BY c1;
+c1 c2 c3
+0 0.0 0
+1 1.0 1
+1 1.0 1
+1 1.0 1
+1 1.0 1
+1 1.0 1
+1 1.0 1
+1 1.0 1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (
+c TEST_INT8,
+c_tinyint TINYINT,
+c_smallint SMALLINT,
+c_mediumint MEDIUMINT,
+c_int INT,
+c_bigint BIGINT
+);
+CREATE TABLE t2 AS SELECT
+LEAST(c,c_tinyint),
+LEAST(c,c_smallint),
+LEAST(c,c_mediumint),
+LEAST(c,c_bigint)
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `LEAST(c,c_tinyint)` test_int8(20) DEFAULT NULL,
+ `LEAST(c,c_smallint)` test_int8(20) DEFAULT NULL,
+ `LEAST(c,c_mediumint)` test_int8(20) DEFAULT NULL,
+ `LEAST(c,c_bigint)` test_int8(20) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (
+c TEST_INT8,
+c_time TIME,
+c_date DATE,
+c_datetime DATETIME,
+c_timestamp TIMESTAMP
+);
+SELECT LEAST(c, c_time) FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and time for operation 'least'
+SELECT LEAST(c, c_date) FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and date for operation 'least'
+SELECT LEAST(c, c_datetime) FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and datetime for operation 'least'
+SELECT LEAST(c, c_timestamp) FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and timestamp for operation 'least'
+DROP TABLE t1;
+CREATE TABLE t1 (
+c TEST_INT8,
+c_char CHAR(32),
+c_varchar VARCHAR(32),
+c_tinytext TINYTEXT,
+c_text TEXT,
+c_mediumtext MEDIUMTEXT,
+c_longtext LONGTEXT
+);
+SELECT LEAST(c, c_char) FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and char for operation 'least'
+SELECT LEAST(c, c_varchar) FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and varchar for operation 'least'
+SELECT LEAST(c, c_tinytext) FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and tinyblob for operation 'least'
+SELECT LEAST(c, c_text) FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and blob for operation 'least'
+SELECT LEAST(c, c_mediumtext) FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and mediumblob for operation 'least'
+SELECT LEAST(c, c_longtext) FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and longblob for operation 'least'
+DROP TABLE t1;
+# Testing aggregation for numeric operation - plus
+CREATE TABLE t1 (a TEST_INT8);
+INSERT INTO t1 VALUES (0),(1),(2),(3),(4),(5),(6),(7);
+CREATE TABLE t2 AS SELECT
+a+1 AS c1,
+a+1.0 AS c2,
+a+1e0 AS c3
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c1` bigint(21) DEFAULT NULL,
+ `c2` decimal(21,1) DEFAULT NULL,
+ `c3` double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM t2 ORDER BY c1;
+c1 c2 c3
+1 1.0 1
+2 2.0 2
+3 3.0 3
+4 4.0 4
+5 5.0 5
+6 6.0 6
+7 7.0 7
+8 8.0 8
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (
+c TEST_INT8,
+c_tinyint TINYINT,
+c_smallint SMALLINT,
+c_mediumint MEDIUMINT,
+c_int INT,
+c_bigint BIGINT
+);
+CREATE TABLE t2 AS SELECT
+c + c_tinyint,
+c + c_smallint,
+c + c_mediumint,
+c + c_bigint
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c + c_tinyint` bigint(21) DEFAULT NULL,
+ `c + c_smallint` bigint(21) DEFAULT NULL,
+ `c + c_mediumint` bigint(21) DEFAULT NULL,
+ `c + c_bigint` bigint(21) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (
+c TEST_INT8,
+c_time TIME,
+c_date DATE,
+c_datetime DATETIME,
+c_timestamp TIMESTAMP
+);
+SELECT c + c_time FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and time for operation '+'
+SELECT c + c_date FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and date for operation '+'
+SELECT c + c_datetime FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and datetime for operation '+'
+SELECT c + c_timestamp FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and timestamp for operation '+'
+DROP TABLE t1;
+CREATE TABLE t1 (
+c TEST_INT8,
+c_char CHAR(32),
+c_varchar VARCHAR(32),
+c_tinytext TINYTEXT,
+c_text TEXT,
+c_mediumtext MEDIUMTEXT,
+c_longtext LONGTEXT
+);
+SELECT c + c_char FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and char for operation '+'
+SELECT c + c_varchar FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and varchar for operation '+'
+SELECT c + c_tinytext FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and tinyblob for operation '+'
+SELECT c + c_text FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and blob for operation '+'
+SELECT c + c_mediumtext FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and mediumblob for operation '+'
+SELECT c + c_longtext FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and longblob for operation '+'
+DROP TABLE t1;
+# Testing aggregation for numeric operation - minus
+CREATE TABLE t1 (a TEST_INT8);
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8);
+CREATE TABLE t2 AS SELECT
+a-1 AS c1,
+a-1.0 AS c2,
+a-1e0 AS c3
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c1` bigint(21) DEFAULT NULL,
+ `c2` decimal(21,1) DEFAULT NULL,
+ `c3` double DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM t2 ORDER BY c1;
+c1 c2 c3
+0 0.0 0
+1 1.0 1
+2 2.0 2
+3 3.0 3
+4 4.0 4
+5 5.0 5
+6 6.0 6
+7 7.0 7
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (
+c TEST_INT8,
+c_tinyint TINYINT,
+c_smallint SMALLINT,
+c_mediumint MEDIUMINT,
+c_int INT,
+c_bigint BIGINT
+);
+CREATE TABLE t2 AS SELECT
+c - c_tinyint,
+c - c_smallint,
+c - c_mediumint,
+c - c_bigint
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c - c_tinyint` bigint(21) DEFAULT NULL,
+ `c - c_smallint` bigint(21) DEFAULT NULL,
+ `c - c_mediumint` bigint(21) DEFAULT NULL,
+ `c - c_bigint` bigint(21) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (
+c TEST_INT8,
+c_time TIME,
+c_date DATE,
+c_datetime DATETIME,
+c_timestamp TIMESTAMP
+);
+SELECT c - c_time FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and time for operation '-'
+SELECT c - c_date FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and date for operation '-'
+SELECT c - c_datetime FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and datetime for operation '-'
+SELECT c - c_timestamp FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and timestamp for operation '-'
+DROP TABLE t1;
+CREATE TABLE t1 (
+c TEST_INT8,
+c_char CHAR(32),
+c_varchar VARCHAR(32),
+c_tinytext TINYTEXT,
+c_text TEXT,
+c_mediumtext MEDIUMTEXT,
+c_longtext LONGTEXT
+);
+SELECT c - c_char FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and char for operation '-'
+SELECT c - c_varchar FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and varchar for operation '-'
+SELECT c - c_tinytext FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and tinyblob for operation '-'
+SELECT c - c_text FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and blob for operation '-'
+SELECT c - c_mediumtext FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and mediumblob for operation '-'
+SELECT c - c_longtext FROM t1;
+ERROR HY000: Illegal parameter data types test_int8 and longblob for operation '-'
+DROP TABLE t1;
+# Testing CAST to other data types
+CREATE TABLE t1 (a TEST_INT8);
+INSERT INTO t1 VALUES (20000102);
+CREATE TABLE t2 AS SELECT
+a,
+CAST(a AS CHAR),
+CAST(a AS DECIMAL),
+CAST(a AS DOUBLE),
+CAST(a AS SIGNED),
+CAST(a AS UNSIGNED),
+CAST(a AS TIME),
+CAST(a AS DATETIME),
+CAST(a AS DATE)
+FROM t1;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` test_int8(20) DEFAULT NULL,
+ `CAST(a AS CHAR)` varchar(20) DEFAULT NULL,
+ `CAST(a AS DECIMAL)` decimal(10,0) DEFAULT NULL,
+ `CAST(a AS DOUBLE)` double DEFAULT NULL,
+ `CAST(a AS SIGNED)` bigint(20) DEFAULT NULL,
+ `CAST(a AS UNSIGNED)` bigint(20) unsigned DEFAULT NULL,
+ `CAST(a AS TIME)` time DEFAULT NULL,
+ `CAST(a AS DATETIME)` datetime DEFAULT NULL,
+ `CAST(a AS DATE)` date DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+SELECT * FROM t2;
+a 20000102
+CAST(a AS CHAR) 20000102
+CAST(a AS DECIMAL) 20000102
+CAST(a AS DOUBLE) 20000102
+CAST(a AS SIGNED) 20000102
+CAST(a AS UNSIGNED) 20000102
+CAST(a AS TIME) 00:00:00
+CAST(a AS DATETIME) 2000-01-02 00:00:00
+CAST(a AS DATE) 2000-01-02
+DROP TABLE t2;
+DROP TABLE t1;
diff --git a/plugin/type_test/mysql-test/type_test/type_test_int8.test b/plugin/type_test/mysql-test/type_test/type_test_int8.test
new file mode 100644
index 00000000..6b5496c3
--- /dev/null
+++ b/plugin/type_test/mysql-test/type_test/type_test_int8.test
@@ -0,0 +1,518 @@
+--echo #
+--echo # MDEV-20016 Add MariaDB_DATA_TYPE_PLUGIN
+--echo #
+
+--vertical_results
+SELECT
+ PLUGIN_NAME,
+ PLUGIN_VERSION,
+ PLUGIN_STATUS,
+ PLUGIN_TYPE,
+ PLUGIN_AUTHOR,
+ PLUGIN_DESCRIPTION,
+ PLUGIN_LICENSE,
+ PLUGIN_MATURITY,
+ PLUGIN_AUTH_VERSION
+FROM INFORMATION_SCHEMA.PLUGINS
+ WHERE PLUGIN_TYPE='DATA TYPE'
+ AND PLUGIN_NAME='test_int8';
+--horizontal_results
+
+CREATE TABLE t1 (a TEST_INT8);
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TEST_INT8(4));
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TEST_INT8(10));
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TEST_INT8(20));
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+
+--disable_ps_protocol
+--enable_metadata
+SELECT CAST('100' AS TEST_INT8) AS cast;
+--disable_metadata
+--enable_ps_protocol
+
+--disable_ps_protocol
+--enable_metadata
+DELIMITER $$;
+BEGIN NOT ATOMIC
+ DECLARE a TEST_INT8 DEFAULT 256;
+ SELECT HEX(a), a;
+END;
+$$
+DELIMITER ;$$
+--disable_metadata
+--enable_ps_protocol
+
+CREATE FUNCTION f1(p TEST_INT8) RETURNS TEST_INT8 RETURN 1;
+SHOW CREATE FUNCTION f1;
+--disable_ps_protocol
+--enable_metadata
+SELECT f1(10);
+--disable_metadata
+--enable_ps_protocol
+DROP FUNCTION f1;
+
+CREATE TABLE t1 (a TEST_INT8);
+CREATE TABLE t2 AS SELECT a FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TEST_INT8);
+CREATE TABLE t2 AS SELECT COALESCE(a,a) FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TEST_INT8);
+CREATE TABLE t2 AS SELECT LEAST(a,a) FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TEST_INT8);
+INSERT INTO t1 VALUES (1),(2);
+CREATE TABLE t2 AS SELECT MIN(a), MAX(a) FROM t1;
+--disable_ps_protocol
+--enable_metadata
+SELECT * FROM t2;
+--disable_metadata
+--enable_ps_protocol
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (id INT, a TEST_INT8);
+INSERT INTO t1 VALUES (1,1),(1,2),(2,1),(2,2);
+CREATE TABLE t2 AS SELECT id, MIN(a), MAX(a) FROM t1 GROUP BY id;
+--disable_ps_protocol
+--enable_metadata
+SELECT * FROM t2;
+--disable_metadata
+--enable_ps_protocol
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TEST_INT8);
+INSERT INTO t1 VALUES (1),(2);
+CREATE TABLE t2 AS SELECT DISTINCT a FROM t1;
+--disable_ps_protocol
+--enable_metadata
+SELECT * FROM t2;
+--disable_metadata
+--enable_ps_protocol
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TEST_INT8);
+INSERT INTO t1 VALUES (1);
+CREATE TABLE t2 AS SELECT (SELECT a FROM t1) AS c1;
+--disable_ps_protocol
+--enable_metadata
+SELECT * FROM t2;
+--disable_metadata
+--enable_ps_protocol
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TEST_INT8);
+CREATE TABLE t2 AS SELECT a FROM t1 UNION SELECT a FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+--echo # Testing CREATE..LIKE
+
+CREATE TABLE t1 (a TEST_INT8);
+CREATE TABLE t2 LIKE t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+--echo # Testing CREATE..SELECT
+
+CREATE TABLE t1 (a TEST_INT8);
+CREATE TABLE t2 AS SELECT * FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+
+--echo # Testing ALTER
+
+CREATE TABLE t1 (a TEST_INT8);
+INSERT INTO t1 VALUES (10),(20);
+SELECT * FROM t1;
+ALTER TABLE t1 MODIFY a INT;
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+ALTER TABLE t1 MODIFY a TEST_INT8;
+SHOW CREATE TABLE t1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (a TEST_INT8);
+INSERT INTO t1 VALUES (10),(20);
+ALTER TABLE t1 ADD b TEST_INT8 DEFAULT 0;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--echo # Testing metadata views
+
+CREATE TABLE t1 (a TEST_INT8);
+--vertical_results
+SELECT
+ TABLE_CATALOG,
+ TABLE_SCHEMA,
+ TABLE_NAME,
+ COLUMN_NAME,
+ ORDINAL_POSITION,
+ COLUMN_DEFAULT,
+ IS_NULLABLE,
+ DATA_TYPE,
+ CHARACTER_MAXIMUM_LENGTH,
+ CHARACTER_OCTET_LENGTH,
+ NUMERIC_PRECISION,
+ NUMERIC_SCALE,
+ DATETIME_PRECISION,
+ CHARACTER_SET_NAME,
+ COLLATION_NAME,
+ COLUMN_TYPE,
+ EXTRA
+FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='t1' AND TABLE_SCHEMA='test';
+--horizontal_results
+SHOW COLUMNS FROM t1;
+DROP TABLE t1;
+
+
+--echo # Testing indexing
+
+CREATE TABLE t1 (a TEST_INT8, KEY(a));
+INSERT INTO t1 VALUES (0),(1),(2),(3),(4),(5),(6),(7);
+EXPLAIN SELECT * FROM t1 WHERE a=3;
+DROP TABLE t1;
+
+--echo # Testing aggregation for result
+
+CREATE TABLE t1 (a TEST_INT8);
+INSERT INTO t1 VALUES (0),(1),(2),(3),(4),(5),(6),(7);
+CREATE TABLE t2 AS SELECT
+ COALESCE(a,1) AS c1,
+ COALESCE(a,1.0) AS c2,
+ COALESCE(a,1e0) AS c3
+FROM t1;
+SHOW CREATE TABLE t2;
+SELECT * FROM t2 ORDER BY c1;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ c TEST_INT8,
+ c_tinyint TINYINT,
+ c_smallint SMALLINT,
+ c_mediumint MEDIUMINT,
+ c_int INT,
+ c_bigint BIGINT
+);
+CREATE TABLE t2 AS SELECT
+ COALESCE(c,c_tinyint),
+ COALESCE(c,c_smallint),
+ COALESCE(c,c_mediumint),
+ COALESCE(c,c_bigint)
+FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ c TEST_INT8,
+ c_time TIME,
+ c_date DATE,
+ c_datetime DATETIME,
+ c_timestamp TIMESTAMP
+);
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT COALESCE(c, c_time) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT COALESCE(c, c_date) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT COALESCE(c, c_datetime) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT COALESCE(c, c_timestamp) FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ c TEST_INT8,
+ c_char CHAR(32),
+ c_varchar VARCHAR(32),
+ c_tinytext TINYTEXT,
+ c_text TEXT,
+ c_mediumtext MEDIUMTEXT,
+ c_longtext LONGTEXT
+);
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT COALESCE(c, c_char) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT COALESCE(c, c_varchar) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT COALESCE(c, c_tinytext) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT COALESCE(c, c_text) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT COALESCE(c, c_mediumtext) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT COALESCE(c, c_longtext) FROM t1;
+DROP TABLE t1;
+
+--echo # Testing aggregation for min/max
+
+CREATE TABLE t1 (a TEST_INT8);
+INSERT INTO t1 VALUES (0),(1),(2),(3),(4),(5),(6),(7);
+CREATE TABLE t2 AS SELECT
+ LEAST(a,1) AS c1,
+ LEAST(a,1.0) AS c2,
+ LEAST(a,1e0) AS c3
+FROM t1;
+SHOW CREATE TABLE t2;
+SELECT * FROM t2 ORDER BY c1;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ c TEST_INT8,
+ c_tinyint TINYINT,
+ c_smallint SMALLINT,
+ c_mediumint MEDIUMINT,
+ c_int INT,
+ c_bigint BIGINT
+);
+CREATE TABLE t2 AS SELECT
+ LEAST(c,c_tinyint),
+ LEAST(c,c_smallint),
+ LEAST(c,c_mediumint),
+ LEAST(c,c_bigint)
+FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ c TEST_INT8,
+ c_time TIME,
+ c_date DATE,
+ c_datetime DATETIME,
+ c_timestamp TIMESTAMP
+);
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT LEAST(c, c_time) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT LEAST(c, c_date) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT LEAST(c, c_datetime) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT LEAST(c, c_timestamp) FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ c TEST_INT8,
+ c_char CHAR(32),
+ c_varchar VARCHAR(32),
+ c_tinytext TINYTEXT,
+ c_text TEXT,
+ c_mediumtext MEDIUMTEXT,
+ c_longtext LONGTEXT
+);
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT LEAST(c, c_char) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT LEAST(c, c_varchar) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT LEAST(c, c_tinytext) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT LEAST(c, c_text) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT LEAST(c, c_mediumtext) FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT LEAST(c, c_longtext) FROM t1;
+DROP TABLE t1;
+
+
+--echo # Testing aggregation for numeric operation - plus
+
+CREATE TABLE t1 (a TEST_INT8);
+INSERT INTO t1 VALUES (0),(1),(2),(3),(4),(5),(6),(7);
+CREATE TABLE t2 AS SELECT
+ a+1 AS c1,
+ a+1.0 AS c2,
+ a+1e0 AS c3
+FROM t1;
+SHOW CREATE TABLE t2;
+SELECT * FROM t2 ORDER BY c1;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ c TEST_INT8,
+ c_tinyint TINYINT,
+ c_smallint SMALLINT,
+ c_mediumint MEDIUMINT,
+ c_int INT,
+ c_bigint BIGINT
+);
+CREATE TABLE t2 AS SELECT
+ c + c_tinyint,
+ c + c_smallint,
+ c + c_mediumint,
+ c + c_bigint
+FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ c TEST_INT8,
+ c_time TIME,
+ c_date DATE,
+ c_datetime DATETIME,
+ c_timestamp TIMESTAMP
+);
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c + c_time FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c + c_date FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c + c_datetime FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c + c_timestamp FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ c TEST_INT8,
+ c_char CHAR(32),
+ c_varchar VARCHAR(32),
+ c_tinytext TINYTEXT,
+ c_text TEXT,
+ c_mediumtext MEDIUMTEXT,
+ c_longtext LONGTEXT
+);
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c + c_char FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c + c_varchar FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c + c_tinytext FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c + c_text FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c + c_mediumtext FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c + c_longtext FROM t1;
+DROP TABLE t1;
+
+--echo # Testing aggregation for numeric operation - minus
+
+CREATE TABLE t1 (a TEST_INT8);
+INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8);
+CREATE TABLE t2 AS SELECT
+ a-1 AS c1,
+ a-1.0 AS c2,
+ a-1e0 AS c3
+FROM t1;
+SHOW CREATE TABLE t2;
+SELECT * FROM t2 ORDER BY c1;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ c TEST_INT8,
+ c_tinyint TINYINT,
+ c_smallint SMALLINT,
+ c_mediumint MEDIUMINT,
+ c_int INT,
+ c_bigint BIGINT
+);
+CREATE TABLE t2 AS SELECT
+ c - c_tinyint,
+ c - c_smallint,
+ c - c_mediumint,
+ c - c_bigint
+FROM t1;
+SHOW CREATE TABLE t2;
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ c TEST_INT8,
+ c_time TIME,
+ c_date DATE,
+ c_datetime DATETIME,
+ c_timestamp TIMESTAMP
+);
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c - c_time FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c - c_date FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c - c_datetime FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c - c_timestamp FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+ c TEST_INT8,
+ c_char CHAR(32),
+ c_varchar VARCHAR(32),
+ c_tinytext TINYTEXT,
+ c_text TEXT,
+ c_mediumtext MEDIUMTEXT,
+ c_longtext LONGTEXT
+);
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c - c_char FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c - c_varchar FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c - c_tinytext FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c - c_text FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c - c_mediumtext FROM t1;
+--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
+SELECT c - c_longtext FROM t1;
+DROP TABLE t1;
+
+
+--echo # Testing CAST to other data types
+
+CREATE TABLE t1 (a TEST_INT8);
+INSERT INTO t1 VALUES (20000102);
+CREATE TABLE t2 AS SELECT
+ a,
+ CAST(a AS CHAR),
+ CAST(a AS DECIMAL),
+ CAST(a AS DOUBLE),
+ CAST(a AS SIGNED),
+ CAST(a AS UNSIGNED),
+ CAST(a AS TIME),
+ CAST(a AS DATETIME),
+ CAST(a AS DATE)
+FROM t1;
+SHOW CREATE TABLE t2;
+--vertical_results
+SELECT * FROM t2;
+--horizontal_results
+DROP TABLE t2;
+DROP TABLE t1;
diff --git a/plugin/type_test/mysql-test/type_test/type_test_mysql.result b/plugin/type_test/mysql-test/type_test/type_test_mysql.result
new file mode 100644
index 00000000..402e8265
--- /dev/null
+++ b/plugin/type_test/mysql-test/type_test/type_test_mysql.result
@@ -0,0 +1,27 @@
+CREATE TABLE t1 (a TEST_INT8, b TEST_DOUBLE);
+Field 1: `a`
+Catalog: `def`
+Database: `test`
+Table: `t1`
+Org_table: `t1`
+Type: LONGLONG
+Collation: binary (63)
+Length: 20
+Max_length: 0
+Decimals: 0
+Flags: NUM
+
+Field 2: `b`
+Catalog: `def`
+Database: `test`
+Table: `t1`
+Org_table: `t1`
+Type: DOUBLE
+Collation: binary (63)
+Length: 22
+Max_length: 0
+Decimals: 31
+Flags: NUM
+
+
+DROP TABLE t1;
diff --git a/plugin/type_test/mysql-test/type_test/type_test_mysql.test b/plugin/type_test/mysql-test/type_test/type_test_mysql.test
new file mode 100644
index 00000000..93a0e08e
--- /dev/null
+++ b/plugin/type_test/mysql-test/type_test/type_test_mysql.test
@@ -0,0 +1,10 @@
+-- source include/have_working_dns.inc
+-- source include/not_embedded.inc
+
+CREATE TABLE t1 (a TEST_INT8, b TEST_DOUBLE);
+#
+# doesn't report the correct type name yet
+# to be fixed
+#
+--exec $MYSQL -t test --column-type-info -e "SELECT * FROM t1" 2>&1
+DROP TABLE t1;
diff --git a/plugin/type_test/plugin.cc b/plugin/type_test/plugin.cc
new file mode 100644
index 00000000..4c26c35f
--- /dev/null
+++ b/plugin/type_test/plugin.cc
@@ -0,0 +1,322 @@
+/*
+ Copyright (c) 2019, MariaDB Corporation
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#include <my_global.h>
+#include <sql_class.h> // THD
+#include <mysql/plugin_data_type.h>
+#include "sql_type.h"
+
+
+class Type_collection_test: public Type_collection
+{
+protected:
+ const Type_handler *aggregate_common(const Type_handler *h1,
+ const Type_handler *h2) const;
+public:
+ const Type_handler *handler_by_name(const LEX_CSTRING &name) const override
+ {
+ return NULL;
+ }
+ const Type_handler *aggregate_for_result(const Type_handler *h1,
+ const Type_handler *h2)
+ const override;
+ const Type_handler *aggregate_for_comparison(const Type_handler *h1,
+ const Type_handler *h2)
+ const override;
+ const Type_handler *aggregate_for_min_max(const Type_handler *h1,
+ const Type_handler *h2)
+ const override;
+ const Type_handler *aggregate_for_num_op(const Type_handler *h1,
+ const Type_handler *h2)
+ const override;
+};
+
+
+static Type_collection_test type_collection_test;
+
+
+class Field_test_int8 :public Field_longlong
+{
+public:
+ Field_test_int8(const LEX_CSTRING &name, const Record_addr &addr,
+ enum utype unireg_check_arg,
+ uint32 len_arg, bool zero_arg, bool unsigned_arg)
+ :Field_longlong(addr.ptr(), len_arg, addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name, zero_arg, unsigned_arg)
+ {}
+ const Type_handler *type_handler() const override;
+};
+
+
+class Type_handler_test_int8: public Type_handler_longlong
+{
+public:
+ const Type_collection *type_collection() const override
+ {
+ return &type_collection_test;
+ }
+ const Type_handler *type_handler_signed() const override
+ {
+ return this;
+ }
+ Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const override
+ {
+ return new (root)
+ Field_test_int8(*name, rec, attr->unireg_check,
+ (uint32) attr->length,
+ f_is_zerofill(attr->pack_flag) != 0,
+ f_is_dec(attr->pack_flag) == 0);
+ }
+};
+
+static Type_handler_test_int8 type_handler_test_int8;
+
+
+const Type_handler *Field_test_int8::type_handler() const
+{
+ return &type_handler_test_int8;
+}
+
+
+static struct st_mariadb_data_type plugin_descriptor_type_test_int8=
+{
+ MariaDB_DATA_TYPE_INTERFACE_VERSION,
+ &type_handler_test_int8
+};
+
+
+/*************************************************************************/
+
+class Field_test_double :public Field_double
+{
+public:
+ Field_test_double(const LEX_CSTRING &name, const Record_addr &addr,
+ enum utype unireg_check_arg,
+ uint32 len_arg, uint8 dec_arg,
+ bool zero_arg, bool unsigned_arg)
+ :Field_double(addr.ptr(), len_arg, addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name, dec_arg, zero_arg, unsigned_arg)
+ {}
+ const Type_handler *type_handler() const override;
+};
+
+
+class Type_handler_test_double: public Type_handler_double
+{
+public:
+ const Type_collection *type_collection() const override
+ {
+ return &type_collection_test;
+ }
+ const Type_handler *type_handler_signed() const override
+ {
+ return this;
+ }
+ bool Column_definition_data_type_info_image(Binary_string *to,
+ const Column_definition &def)
+ const override
+ {
+ return to->append(Type_handler_test_double::name().lex_cstring());
+ }
+ Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const override
+ {
+ return new (root)
+ Field_test_double(*name, rec, attr->unireg_check,
+ (uint32) attr->length, (uint8) attr->decimals,
+ f_is_zerofill(attr->pack_flag) != 0,
+ f_is_dec(attr->pack_flag) == 0);
+ }
+};
+
+static Type_handler_test_double type_handler_test_double;
+
+
+const Type_handler *Field_test_double::type_handler() const
+{
+ return &type_handler_test_double;
+}
+
+
+static struct st_mariadb_data_type plugin_descriptor_type_test_double=
+{
+ MariaDB_DATA_TYPE_INTERFACE_VERSION,
+ &type_handler_test_double
+};
+
+
+/*************************************************************************/
+const Type_handler *
+Type_collection_test::aggregate_common(const Type_handler *h1,
+ const Type_handler *h2) const
+{
+ if (h1 == h2)
+ return h1;
+
+ static const Type_aggregator::Pair agg[]=
+ {
+ {
+ &type_handler_slong,
+ &type_handler_test_double,
+ &type_handler_test_double
+ },
+ {
+ &type_handler_newdecimal,
+ &type_handler_test_double,
+ &type_handler_test_double
+ },
+ {
+ &type_handler_double,
+ &type_handler_test_double,
+ &type_handler_test_double
+ },
+ {
+ &type_handler_slong,
+ &type_handler_test_int8,
+ &type_handler_test_int8
+ },
+ {
+ &type_handler_newdecimal,
+ &type_handler_test_int8,
+ &type_handler_newdecimal
+ },
+ {
+ &type_handler_double,
+ &type_handler_test_int8,
+ &type_handler_double
+ },
+ {
+ &type_handler_stiny,
+ &type_handler_test_double,
+ &type_handler_test_double
+ },
+ {
+ &type_handler_sshort,
+ &type_handler_test_double,
+ &type_handler_test_double
+ },
+ {
+ &type_handler_sint24,
+ &type_handler_test_double,
+ &type_handler_test_double
+ },
+ {
+ &type_handler_slonglong,
+ &type_handler_test_double,
+ &type_handler_test_double
+ },
+ {
+ &type_handler_stiny,
+ &type_handler_test_int8,
+ &type_handler_test_int8
+ },
+ {
+ &type_handler_sshort,
+ &type_handler_test_int8,
+ &type_handler_test_int8
+ },
+ {
+ &type_handler_sint24,
+ &type_handler_test_int8,
+ &type_handler_test_int8
+ },
+ {
+ &type_handler_slonglong,
+ &type_handler_test_int8,
+ &type_handler_test_int8
+ },
+ {NULL,NULL,NULL}
+ };
+
+ return Type_aggregator::find_handler_in_array(agg, h1, h2, true);
+}
+
+
+const Type_handler *
+Type_collection_test::aggregate_for_result(const Type_handler *h1,
+ const Type_handler *h2) const
+{
+ return aggregate_common(h1, h2);
+}
+
+
+const Type_handler *
+Type_collection_test::aggregate_for_min_max(const Type_handler *h1,
+ const Type_handler *h2) const
+{
+ return aggregate_common(h1, h2);
+}
+
+
+const Type_handler *
+Type_collection_test::aggregate_for_num_op(const Type_handler *h1,
+ const Type_handler *h2) const
+{
+ return aggregate_common(h1, h2);
+}
+
+
+const Type_handler *
+Type_collection_test::aggregate_for_comparison(const Type_handler *h1,
+ const Type_handler *h2) const
+{
+ DBUG_ASSERT(h1 == h1->type_handler_for_comparison());
+ DBUG_ASSERT(h2 == h2->type_handler_for_comparison());
+ return aggregate_common(h1, h2);
+}
+
+
+/*************************************************************************/
+
+maria_declare_plugin(type_test)
+{
+ MariaDB_DATA_TYPE_PLUGIN, // the plugin type (see include/mysql/plugin.h)
+ &plugin_descriptor_type_test_int8, // pointer to type-specific plugin descriptor
+ "test_int8", // plugin name
+ "MariaDB Corporation", // plugin author
+ "Data type TEST_INT8", // the plugin description
+ PLUGIN_LICENSE_GPL, // the plugin license (see include/mysql/plugin.h)
+ 0, // Pointer to plugin initialization function
+ 0, // Pointer to plugin deinitialization function
+ 0x0100, // Numeric version 0xAABB means AA.BB version
+ NULL, // Status variables
+ NULL, // System variables
+ "1.0", // String version representation
+ MariaDB_PLUGIN_MATURITY_EXPERIMENTAL // Maturity(see include/mysql/plugin.h)*/
+},
+{
+ MariaDB_DATA_TYPE_PLUGIN, // the plugin type (see include/mysql/plugin.h)
+ &plugin_descriptor_type_test_double, // pointer to type-specific plugin descriptor
+ "test_double", // plugin name
+ "MariaDB Corporation", // plugin author
+ "Data type TEST_DOUBLE", // the plugin description
+ PLUGIN_LICENSE_GPL, // the plugin license (see include/mysql/plugin.h)
+ 0, // Pointer to plugin initialization function
+ 0, // Pointer to plugin deinitialization function
+ 0x0100, // Numeric version 0xAABB means AA.BB version
+ NULL, // Status variables
+ NULL, // System variables
+ "1.0", // String version representation
+ MariaDB_PLUGIN_MATURITY_EXPERIMENTAL // Maturity(see include/mysql/plugin.h)*/
+}
+maria_declare_plugin_end;
diff --git a/plugin/user_variables/CMakeLists.txt b/plugin/user_variables/CMakeLists.txt
new file mode 100644
index 00000000..6638a5cb
--- /dev/null
+++ b/plugin/user_variables/CMakeLists.txt
@@ -0,0 +1,2 @@
+MYSQL_ADD_PLUGIN(user_variables user_variables.cc
+ DEFAULT RECOMPILE_FOR_EMBEDDED)
diff --git a/plugin/user_variables/mysql-test/user_variables/basic.result b/plugin/user_variables/mysql-test/user_variables/basic.result
new file mode 100644
index 00000000..a4d01957
--- /dev/null
+++ b/plugin/user_variables/mysql-test/user_variables/basic.result
@@ -0,0 +1,63 @@
+SELECT PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_STATUS, PLUGIN_TYPE, PLUGIN_AUTHOR, PLUGIN_DESCRIPTION, PLUGIN_LICENSE, LOAD_OPTION, PLUGIN_MATURITY FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME='user_variables';
+PLUGIN_NAME user_variables
+PLUGIN_VERSION 1.0
+PLUGIN_STATUS ACTIVE
+PLUGIN_TYPE INFORMATION SCHEMA
+PLUGIN_AUTHOR Sergey Vojtovich
+PLUGIN_DESCRIPTION User-defined variables
+PLUGIN_LICENSE GPL
+LOAD_OPTION ON
+PLUGIN_MATURITY Stable
+SHOW CREATE TABLE INFORMATION_SCHEMA.USER_VARIABLES;
+Table Create Table
+user_variables CREATE TEMPORARY TABLE `user_variables` (
+ `VARIABLE_NAME` varchar(64) NOT NULL DEFAULT '',
+ `VARIABLE_VALUE` varchar(2048) DEFAULT NULL,
+ `VARIABLE_TYPE` varchar(64) NOT NULL DEFAULT '',
+ `CHARACTER_SET_NAME` varchar(32) DEFAULT NULL
+) ENGINE=MEMORY DEFAULT CHARSET=utf8
+FLUSH USER_VARIABLES;
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.USER_VARIABLES;
+COUNT(*)
+0
+SET @int_var=1;
+SET @uint_var=CAST(2 AS UNSIGNED INTEGER);
+SET @str_var='Value of string variable';
+SET @utf8str_var=_utf8 'UTF8 string value';
+SET @double_var=CAST(1 AS DOUBLE);
+SET @dec_var=CAST(1 AS DECIMAL(20, 10));
+SET @time_var=CAST('2016-02-25' AS DATE);
+SET @' @#^%'='Value of variable with odd name';
+SET @''='Value of variable with empty name';
+SET @null_var=NULL;
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.USER_VARIABLES;
+COUNT(*)
+10
+SELECT * FROM INFORMATION_SCHEMA.USER_VARIABLES ORDER BY VARIABLE_NAME;
+VARIABLE_NAME VARIABLE_VALUE VARIABLE_TYPE CHARACTER_SET_NAME
+ Value of variable with empty name VARCHAR latin1
+ @#^% Value of variable with odd name VARCHAR latin1
+dec_var 1.0000000000 DECIMAL latin1
+double_var 1 DOUBLE latin1
+int_var 1 INT latin1
+null_var NULL VARCHAR binary
+str_var Value of string variable VARCHAR latin1
+time_var 2016-02-25 VARCHAR latin1
+uint_var 2 INT UNSIGNED latin1
+utf8str_var UTF8 string value VARCHAR utf8
+SHOW USER_VARIABLES;
+Variable_name Value
+ Value of variable with empty name
+ @#^% Value of variable with odd name
+dec_var 1.0000000000
+double_var 1
+int_var 1
+null_var NULL
+str_var Value of string variable
+time_var 2016-02-25
+uint_var 2
+utf8str_var UTF8 string value
+FLUSH USER_VARIABLES;
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.USER_VARIABLES;
+COUNT(*)
+0
diff --git a/plugin/user_variables/mysql-test/user_variables/basic.test b/plugin/user_variables/mysql-test/user_variables/basic.test
new file mode 100644
index 00000000..7e67e4fa
--- /dev/null
+++ b/plugin/user_variables/mysql-test/user_variables/basic.test
@@ -0,0 +1,24 @@
+query_vertical SELECT PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_STATUS, PLUGIN_TYPE, PLUGIN_AUTHOR, PLUGIN_DESCRIPTION, PLUGIN_LICENSE, LOAD_OPTION, PLUGIN_MATURITY FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME='user_variables';
+SHOW CREATE TABLE INFORMATION_SCHEMA.USER_VARIABLES;
+
+FLUSH USER_VARIABLES;
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.USER_VARIABLES;
+
+SET @int_var=1;
+SET @uint_var=CAST(2 AS UNSIGNED INTEGER);
+SET @str_var='Value of string variable';
+SET @utf8str_var=_utf8 'UTF8 string value';
+SET @double_var=CAST(1 AS DOUBLE);
+SET @dec_var=CAST(1 AS DECIMAL(20, 10));
+SET @time_var=CAST('2016-02-25' AS DATE);
+SET @' @#^%'='Value of variable with odd name';
+SET @''='Value of variable with empty name';
+SET @null_var=NULL;
+
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.USER_VARIABLES;
+SELECT * FROM INFORMATION_SCHEMA.USER_VARIABLES ORDER BY VARIABLE_NAME;
+--sorted_result
+SHOW USER_VARIABLES;
+
+FLUSH USER_VARIABLES;
+SELECT COUNT(*) FROM INFORMATION_SCHEMA.USER_VARIABLES;
diff --git a/plugin/user_variables/mysql-test/user_variables/suite.opt b/plugin/user_variables/mysql-test/user_variables/suite.opt
new file mode 100644
index 00000000..6140014d
--- /dev/null
+++ b/plugin/user_variables/mysql-test/user_variables/suite.opt
@@ -0,0 +1 @@
+--plugin-load-add=$USER_VARIABLES_SO --plugin-user-variables=ON
diff --git a/plugin/user_variables/mysql-test/user_variables/suite.pm b/plugin/user_variables/mysql-test/user_variables/suite.pm
new file mode 100644
index 00000000..b927bf40
--- /dev/null
+++ b/plugin/user_variables/mysql-test/user_variables/suite.pm
@@ -0,0 +1,14 @@
+package My::Suite::User_variables;
+
+@ISA = qw(My::Suite);
+
+return "No USER_VARIABLES plugin" unless
+ $ENV{USER_VARIABLES_SO} or
+ $::mysqld_variables{'user-variables'} eq "ON";
+
+return "Not run for embedded server" if $::opt_embedded_server and
+ $ENV{USER_VARIABLES_SO};
+
+sub is_default { 1 }
+
+bless { };
diff --git a/plugin/user_variables/user_variables.cc b/plugin/user_variables/user_variables.cc
new file mode 100644
index 00000000..f820e4ad
--- /dev/null
+++ b/plugin/user_variables/user_variables.cc
@@ -0,0 +1,142 @@
+/* Copyright (C) 2016 MariaDB Foundation and Sergey Vojtovich
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1335 USA */
+
+#define MYSQL_SERVER
+#include <my_global.h>
+#include <sql_class.h>
+#include <sql_i_s.h>
+#include <sql_show.h>
+
+
+static const LEX_CSTRING result_types[]=
+{
+ { STRING_WITH_LEN("VARCHAR") },
+ { STRING_WITH_LEN("DOUBLE") },
+ { STRING_WITH_LEN("INT") },
+ { STRING_WITH_LEN("<IMPOSSIBLE1>") }, // ROW_RESULT
+ { STRING_WITH_LEN("DECIMAL") },
+ { STRING_WITH_LEN("<IMPOSSIBLE2>")} // TIME_RESULT
+};
+
+
+static const LEX_CSTRING unsigned_result_types[]=
+{
+ { STRING_WITH_LEN("<IMPOSSIBLE3>") }, // UNSIGNED STRING_RESULT
+ { STRING_WITH_LEN("DOUBLE UNSIGNED") },
+ { STRING_WITH_LEN("INT UNSIGNED") },
+ { STRING_WITH_LEN("<IMPOSSIBLE4>") }, // UNSIGNED ROW_RESULT
+ { STRING_WITH_LEN("DECIMAL UNSIGNED") },
+ { STRING_WITH_LEN("<IMPOSSIBLE5>") } // UNSIGNED TIME_RESULT
+};
+
+
+namespace Show {
+
+static ST_FIELD_INFO user_variables_fields_info[] =
+{
+ Column("VARIABLE_NAME", Name(), NOT_NULL, "Variable_name"),
+ Column("VARIABLE_VALUE", Varchar(2048), NULLABLE, "Value"),
+ Column("VARIABLE_TYPE", Name(), NOT_NULL),
+ Column("CHARACTER_SET_NAME", CSName(), NULLABLE),
+ CEnd()
+};
+
+} // namespace Show
+
+static int user_variables_fill(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+ ulong i;
+ TABLE *table= tables->table;
+ Field **field= table->field;
+ String buff;
+ bool is_null;
+
+ for (i= 0; i < thd->user_vars.records; i++)
+ {
+ user_var_entry *var= (user_var_entry*) my_hash_element(&thd->user_vars, i);
+
+ field[0]->store(var->name.str, var->name.length, system_charset_info);
+
+ if (var->val_str(&is_null, &buff, NOT_FIXED_DEC))
+ {
+ field[1]->store(buff.ptr(), buff.length(), buff.charset());
+ field[1]->set_notnull();
+ }
+ else if (is_null)
+ field[1]->set_null();
+ else
+ return 1;
+
+ const LEX_CSTRING *tmp= var->unsigned_flag ?
+ &unsigned_result_types[var->type] :
+ &result_types[var->type];
+ field[2]->store(tmp->str, tmp->length, system_charset_info);
+
+ if (var->charset())
+ {
+ field[3]->store(var->charset()->csname, strlen(var->charset()->csname),
+ system_charset_info);
+ field[3]->set_notnull();
+ }
+ else
+ field[3]->set_null();
+
+ if (schema_table_store_record(thd, table))
+ return 1;
+ }
+ return 0;
+}
+
+
+int user_variables_reset(void)
+{
+ THD *thd= current_thd;
+ if (thd)
+ my_hash_reset(&thd->user_vars);
+ return 0;
+}
+
+
+static int user_variables_init(void *p)
+{
+ ST_SCHEMA_TABLE *is= (ST_SCHEMA_TABLE *) p;
+ is->fields_info= Show::user_variables_fields_info;
+ is->fill_table= user_variables_fill;
+ is->reset_table= user_variables_reset;
+ return 0;
+}
+
+
+static struct st_mysql_information_schema user_variables_descriptor=
+{ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+
+maria_declare_plugin(user_variables)
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &user_variables_descriptor,
+ "user_variables",
+ "Sergey Vojtovich",
+ "User-defined variables",
+ PLUGIN_LICENSE_GPL,
+ user_variables_init,
+ NULL,
+ 0x0100,
+ NULL,
+ NULL,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
diff --git a/plugin/userstat/CMakeLists.txt b/plugin/userstat/CMakeLists.txt
new file mode 100644
index 00000000..5daa4f59
--- /dev/null
+++ b/plugin/userstat/CMakeLists.txt
@@ -0,0 +1,4 @@
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql)
+
+MYSQL_ADD_PLUGIN(USERSTAT userstat.cc MANDATORY)
+
diff --git a/plugin/userstat/client_stats.cc b/plugin/userstat/client_stats.cc
new file mode 100644
index 00000000..72c71785
--- /dev/null
+++ b/plugin/userstat/client_stats.cc
@@ -0,0 +1,103 @@
+namespace Show {
+
+static ST_FIELD_INFO client_stats_fields[]=
+{
+ Column("CLIENT",Varchar(LIST_PROCESS_HOST_LEN), NOT_NULL, "Client"),
+ Column("TOTAL_CONNECTIONS", SLonglong(), NOT_NULL, "Total_connections"),
+ Column("CONCURRENT_CONNECTIONS", SLonglong(), NOT_NULL, "Concurrent_connections"),
+ Column("CONNECTED_TIME", SLonglong(), NOT_NULL, "Connected_time"),
+ Column("BUSY_TIME", Double(MY_INT64_NUM_DECIMAL_DIGITS), NOT_NULL, "Busy_time"),
+ Column("CPU_TIME", Double(MY_INT64_NUM_DECIMAL_DIGITS), NOT_NULL, "Cpu_time"),
+ Column("BYTES_RECEIVED", SLonglong(), NOT_NULL, "Bytes_received"),
+ Column("BYTES_SENT", SLonglong(), NOT_NULL, "Bytes_sent"),
+ Column("BINLOG_BYTES_WRITTEN", SLonglong(), NOT_NULL, "Binlog_bytes_written"),
+ Column("ROWS_READ", SLonglong(), NOT_NULL, "Rows_read"),
+ Column("ROWS_SENT", SLonglong(), NOT_NULL, "Rows_sent"),
+ Column("ROWS_DELETED", SLonglong(), NOT_NULL, "Rows_deleted"),
+ Column("ROWS_INSERTED", SLonglong(), NOT_NULL, "Rows_inserted"),
+ Column("ROWS_UPDATED", SLonglong(), NOT_NULL, "Rows_updated"),
+ Column("SELECT_COMMANDS", SLonglong(), NOT_NULL, "Select_commands"),
+ Column("UPDATE_COMMANDS", SLonglong(), NOT_NULL, "Update_commands"),
+ Column("OTHER_COMMANDS", SLonglong(), NOT_NULL, "Other_commands"),
+ Column("COMMIT_TRANSACTIONS", SLonglong(), NOT_NULL, "Commit_transactions"),
+ Column("ROLLBACK_TRANSACTIONS", SLonglong(), NOT_NULL, "Rollback_transactions"),
+ Column("DENIED_CONNECTIONS", SLonglong(), NOT_NULL, "Denied_connections"),
+ Column("LOST_CONNECTIONS", SLonglong(), NOT_NULL, "Lost_connections"),
+ Column("ACCESS_DENIED", SLonglong(), NOT_NULL, "Access_denied"),
+ Column("EMPTY_QUERIES", SLonglong(), NOT_NULL, "Empty_queries"),
+ Column("TOTAL_SSL_CONNECTIONS", ULonglong(), NOT_NULL, "Total_ssl_connections"),
+ Column("MAX_STATEMENT_TIME_EXCEEDED", SLonglong(), NOT_NULL, "Max_statement_time_exceeded"),
+ CEnd()
+};
+
+} // namespace Show
+
+static int send_user_stats(THD* thd, HASH *all_user_stats, TABLE *table)
+{
+ mysql_mutex_lock(&LOCK_global_user_client_stats);
+ for (uint i= 0; i < all_user_stats->records; i++)
+ {
+ uint j= 0;
+ USER_STATS *user_stats= (USER_STATS*) my_hash_element(all_user_stats, i);
+
+ table->field[j++]->store(user_stats->user, user_stats->user_name_length,
+ system_charset_info);
+ table->field[j++]->store((longlong)user_stats->total_connections,TRUE);
+ table->field[j++]->store((longlong)user_stats->concurrent_connections, TRUE);
+ table->field[j++]->store((longlong)user_stats->connected_time, TRUE);
+ table->field[j++]->store((double)user_stats->busy_time);
+ table->field[j++]->store((double)user_stats->cpu_time);
+ table->field[j++]->store((longlong)user_stats->bytes_received, TRUE);
+ table->field[j++]->store((longlong)user_stats->bytes_sent, TRUE);
+ table->field[j++]->store((longlong)user_stats->binlog_bytes_written, TRUE);
+ table->field[j++]->store((longlong)user_stats->rows_read, TRUE);
+ table->field[j++]->store((longlong)user_stats->rows_sent, TRUE);
+ table->field[j++]->store((longlong)user_stats->rows_deleted, TRUE);
+ table->field[j++]->store((longlong)user_stats->rows_inserted, TRUE);
+ table->field[j++]->store((longlong)user_stats->rows_updated, TRUE);
+ table->field[j++]->store((longlong)user_stats->select_commands, TRUE);
+ table->field[j++]->store((longlong)user_stats->update_commands, TRUE);
+ table->field[j++]->store((longlong)user_stats->other_commands, TRUE);
+ table->field[j++]->store((longlong)user_stats->commit_trans, TRUE);
+ table->field[j++]->store((longlong)user_stats->rollback_trans, TRUE);
+ table->field[j++]->store((longlong)user_stats->denied_connections, TRUE);
+ table->field[j++]->store((longlong)user_stats->lost_connections, TRUE);
+ table->field[j++]->store((longlong)user_stats->access_denied_errors, TRUE);
+ table->field[j++]->store((longlong)user_stats->empty_queries, TRUE);
+ table->field[j++]->store((longlong)user_stats->total_ssl_connections, TRUE);
+ table->field[j++]->store((longlong)user_stats->max_statement_time_exceeded, TRUE);
+ if (schema_table_store_record(thd, table))
+ {
+ mysql_mutex_unlock(&LOCK_global_user_client_stats);
+ return 1;
+ }
+ }
+ mysql_mutex_unlock(&LOCK_global_user_client_stats);
+ return 0;
+}
+
+static int client_stats_fill(THD* thd, TABLE_LIST* tables, COND* cond)
+{
+ if (check_global_access(thd, PROCESS_ACL, true))
+ return 0;
+
+ return send_user_stats(thd, &global_client_stats, tables->table);
+}
+
+static int client_stats_reset()
+{
+ mysql_mutex_lock(&LOCK_global_user_client_stats);
+ free_global_client_stats();
+ init_global_client_stats();
+ mysql_mutex_unlock(&LOCK_global_user_client_stats);
+ return 0;
+}
+
+static int client_stats_init(void *p)
+{
+ ST_SCHEMA_TABLE *schema= (ST_SCHEMA_TABLE *)p;
+ schema->fields_info= Show::client_stats_fields;
+ schema->fill_table= client_stats_fill;
+ schema->reset_table= client_stats_reset;
+ return 0;
+}
diff --git a/plugin/userstat/index_stats.cc b/plugin/userstat/index_stats.cc
new file mode 100644
index 00000000..97305e89
--- /dev/null
+++ b/plugin/userstat/index_stats.cc
@@ -0,0 +1,75 @@
+namespace Show {
+
+static ST_FIELD_INFO index_stats_fields[]=
+{
+ Column("TABLE_SCHEMA", Varchar(NAME_LEN), NOT_NULL, "Table_schema"),
+ Column("TABLE_NAME", Varchar(NAME_LEN), NOT_NULL, "Table_name"),
+ Column("INDEX_NAME", Varchar(NAME_LEN), NOT_NULL, "Index_name"),
+ Column("ROWS_READ", SLonglong(), NOT_NULL, "Rows_read"),
+ CEnd()
+};
+
+} // namespace Show
+
+static int index_stats_fill(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+ TABLE *table= tables->table;
+
+ mysql_mutex_lock(&LOCK_global_index_stats);
+ for (uint i= 0; i < global_index_stats.records; i++)
+ {
+ INDEX_STATS *index_stats =
+ (INDEX_STATS*) my_hash_element(&global_index_stats, i);
+ TABLE_LIST tmp_table;
+ const char *index_name;
+ size_t index_name_length;
+
+ bzero((char*) &tmp_table,sizeof(tmp_table));
+ tmp_table.db.str= index_stats->index;
+ tmp_table.db.length= strlen(index_stats->index);
+ tmp_table.table_name.str= index_stats->index + tmp_table.db.length + 1;
+ tmp_table.table_name.length= strlen(tmp_table.table_name.str);
+ tmp_table.grant.privilege= NO_ACL;
+ if (check_access(thd, SELECT_ACL, tmp_table.db.str,
+ &tmp_table.grant.privilege, NULL, 0, 1) ||
+ check_grant(thd, SELECT_ACL, &tmp_table, 1, 1, 1))
+ continue;
+
+ index_name= tmp_table.table_name.str + tmp_table.table_name.length + 1;
+ index_name_length= (index_stats->index_name_length - tmp_table.db.length -
+ tmp_table.table_name.length - 3);
+
+ table->field[0]->store(tmp_table.db.str, tmp_table.db.length, system_charset_info);
+ table->field[1]->store(tmp_table.table_name.str, tmp_table.table_name.length,
+ system_charset_info);
+ table->field[2]->store(index_name, (uint) index_name_length, system_charset_info);
+ table->field[3]->store((longlong)index_stats->rows_read, TRUE);
+
+ if (schema_table_store_record(thd, table))
+ {
+ mysql_mutex_unlock(&LOCK_global_index_stats);
+ return 1;
+ }
+ }
+ mysql_mutex_unlock(&LOCK_global_index_stats);
+ return 0;
+}
+
+static int index_stats_reset()
+{
+ mysql_mutex_lock(&LOCK_global_index_stats);
+ free_global_index_stats();
+ init_global_index_stats();
+ mysql_mutex_unlock(&LOCK_global_index_stats);
+ return 0;
+}
+
+static int index_stats_init(void *p)
+{
+ ST_SCHEMA_TABLE *schema= (ST_SCHEMA_TABLE *)p;
+ schema->fields_info= Show::index_stats_fields;
+ schema->fill_table= index_stats_fill;
+ schema->reset_table= index_stats_reset;
+ return 0;
+}
+
diff --git a/plugin/userstat/table_stats.cc b/plugin/userstat/table_stats.cc
new file mode 100644
index 00000000..0a656793
--- /dev/null
+++ b/plugin/userstat/table_stats.cc
@@ -0,0 +1,78 @@
+namespace Show {
+
+static ST_FIELD_INFO table_stats_fields[]=
+{
+ Column("TABLE_SCHEMA", Varchar(NAME_LEN), NOT_NULL, "Table_schema"),
+ Column("TABLE_NAME", Varchar(NAME_LEN), NOT_NULL, "Table_name"),
+ Column("ROWS_READ", SLonglong(), NOT_NULL, "Rows_read"),
+ Column("ROWS_CHANGED", SLonglong(), NOT_NULL, "Rows_changed"),
+ Column("ROWS_CHANGED_X_INDEXES",SLonglong(), NOT_NULL, "Rows_changed_x_#indexes"),
+ CEnd()
+};
+
+} // namespace Show
+
+static int table_stats_fill(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+ TABLE *table= tables->table;
+
+ mysql_mutex_lock(&LOCK_global_table_stats);
+ for (uint i= 0; i < global_table_stats.records; i++)
+ {
+ char *end_of_schema;
+ TABLE_STATS *table_stats=
+ (TABLE_STATS*)my_hash_element(&global_table_stats, i);
+ TABLE_LIST tmp_table;
+ size_t schema_length, table_name_length;
+
+ end_of_schema= strend(table_stats->table);
+ schema_length= (size_t) (end_of_schema - table_stats->table);
+ table_name_length= strlen(table_stats->table + schema_length + 1);
+
+ bzero((char*) &tmp_table,sizeof(tmp_table));
+ tmp_table.db.str= table_stats->table;
+ tmp_table.db.length= schema_length;
+ tmp_table.table_name.str= end_of_schema+1;
+ tmp_table.table_name.length= table_name_length;
+ tmp_table.grant.privilege= NO_ACL;
+ if (check_access(thd, SELECT_ACL, tmp_table.db.str,
+ &tmp_table.grant.privilege, NULL, 0, 1) ||
+ check_grant(thd, SELECT_ACL, &tmp_table, 1, 1, 1))
+ continue;
+
+ table->field[0]->store(table_stats->table, schema_length,
+ system_charset_info);
+ table->field[1]->store(table_stats->table + schema_length+1,
+ table_name_length, system_charset_info);
+ table->field[2]->store((longlong)table_stats->rows_read, TRUE);
+ table->field[3]->store((longlong)table_stats->rows_changed, TRUE);
+ table->field[4]->store((longlong)table_stats->rows_changed_x_indexes,
+ TRUE);
+ if (schema_table_store_record(thd, table))
+ {
+ mysql_mutex_unlock(&LOCK_global_table_stats);
+ return 1;
+ }
+ }
+ mysql_mutex_unlock(&LOCK_global_table_stats);
+ return 0;
+}
+
+static int table_stats_reset()
+{
+ mysql_mutex_lock(&LOCK_global_table_stats);
+ free_global_table_stats();
+ init_global_table_stats();
+ mysql_mutex_unlock(&LOCK_global_table_stats);
+ return 0;
+}
+
+static int table_stats_init(void *p)
+{
+ ST_SCHEMA_TABLE *schema= (ST_SCHEMA_TABLE *)p;
+ schema->fields_info= Show::table_stats_fields;
+ schema->fill_table= table_stats_fill;
+ schema->reset_table= table_stats_reset;
+ return 0;
+}
+
diff --git a/plugin/userstat/user_stats.cc b/plugin/userstat/user_stats.cc
new file mode 100644
index 00000000..de3d4e12
--- /dev/null
+++ b/plugin/userstat/user_stats.cc
@@ -0,0 +1,60 @@
+namespace Show {
+
+static ST_FIELD_INFO user_stats_fields[]=
+{
+ Column("USER",Varchar(USERNAME_CHAR_LENGTH),NOT_NULL, "User"),
+ Column("TOTAL_CONNECTIONS", SLong(), NOT_NULL, "Total_connections"),
+ Column("CONCURRENT_CONNECTIONS",SLong(), NOT_NULL, "Concurrent_connections"),
+ Column("CONNECTED_TIME", SLong(), NOT_NULL, "Connected_time"),
+ Column("BUSY_TIME", Double(MY_INT64_NUM_DECIMAL_DIGITS), NOT_NULL, "Busy_time"),
+ Column("CPU_TIME", Double(MY_INT64_NUM_DECIMAL_DIGITS), NOT_NULL, "Cpu_time"),
+ Column("BYTES_RECEIVED", SLonglong(), NOT_NULL, "Bytes_received"),
+ Column("BYTES_SENT", SLonglong(), NOT_NULL, "Bytes_sent"),
+ Column("BINLOG_BYTES_WRITTEN", SLonglong(), NOT_NULL, "Binlog_bytes_written"),
+ Column("ROWS_READ", SLonglong(), NOT_NULL, "Rows_read"),
+ Column("ROWS_SENT", SLonglong(), NOT_NULL, "Rows_sent"),
+ Column("ROWS_DELETED", SLonglong(), NOT_NULL, "Rows_deleted"),
+ Column("ROWS_INSERTED", SLonglong(), NOT_NULL, "Rows_inserted"),
+ Column("ROWS_UPDATED", SLonglong(), NOT_NULL, "Rows_updated"),
+ Column("SELECT_COMMANDS", SLonglong(), NOT_NULL, "Select_commands"),
+ Column("UPDATE_COMMANDS", SLonglong(), NOT_NULL, "Update_commands"),
+ Column("OTHER_COMMANDS", SLonglong(), NOT_NULL, "Other_commands"),
+ Column("COMMIT_TRANSACTIONS", SLonglong(), NOT_NULL, "Commit_transactions"),
+ Column("ROLLBACK_TRANSACTIONS",SLonglong(), NOT_NULL, "Rollback_transactions"),
+ Column("DENIED_CONNECTIONS", SLonglong(), NOT_NULL, "Denied_connections"),
+ Column("LOST_CONNECTIONS", SLonglong(), NOT_NULL, "Lost_connections"),
+ Column("ACCESS_DENIED", SLonglong(), NOT_NULL, "Access_denied"),
+ Column("EMPTY_QUERIES", SLonglong(), NOT_NULL, "Empty_queries"),
+ Column("TOTAL_SSL_CONNECTIONS",ULonglong(), NOT_NULL, "Total_ssl_connections"),
+ Column("MAX_STATEMENT_TIME_EXCEEDED",SLonglong(),NOT_NULL, "Max_statement_time_exceeded"),
+ CEnd()
+};
+
+} // namespace Show
+
+static int user_stats_fill(THD* thd, TABLE_LIST* tables, COND* cond)
+{
+ if (check_global_access(thd, PROCESS_ACL, true))
+ return 0;
+
+ return send_user_stats(thd, &global_user_stats, tables->table);
+}
+
+static int user_stats_reset()
+{
+ mysql_mutex_lock(&LOCK_global_user_client_stats);
+ free_global_user_stats();
+ init_global_user_stats();
+ mysql_mutex_unlock(&LOCK_global_user_client_stats);
+ return 0;
+}
+
+static int user_stats_init(void *p)
+{
+ ST_SCHEMA_TABLE *schema= (ST_SCHEMA_TABLE *)p;
+ schema->fields_info= Show::user_stats_fields;
+ schema->fill_table= user_stats_fill;
+ schema->reset_table= user_stats_reset;
+ return 0;
+}
+
diff --git a/plugin/userstat/userstat.cc b/plugin/userstat/userstat.cc
new file mode 100644
index 00000000..2084453f
--- /dev/null
+++ b/plugin/userstat/userstat.cc
@@ -0,0 +1,82 @@
+#include <my_global.h>
+#include <mysql/plugin.h>
+#include <mysql_version.h>
+#include "table.h"
+#include "sql_connect.h"
+#include "field.h"
+#include "sql_const.h"
+#include "sql_acl.h"
+
+bool schema_table_store_record(THD *thd, TABLE *table);
+
+#include "client_stats.cc"
+#include "index_stats.cc"
+#include "table_stats.cc"
+#include "user_stats.cc"
+
+static struct st_mysql_information_schema userstat_info=
+{ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+maria_declare_plugin(userstat)
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &userstat_info,
+ "CLIENT_STATISTICS",
+ "Percona and Sergei Golubchik",
+ "Client Statistics",
+ PLUGIN_LICENSE_GPL,
+ client_stats_init,
+ 0,
+ 0x0200,
+ NULL,
+ NULL,
+ "2.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+},
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &userstat_info,
+ "INDEX_STATISTICS",
+ "Percona and Sergei Golubchik",
+ "Index Statistics",
+ PLUGIN_LICENSE_GPL,
+ index_stats_init,
+ 0,
+ 0x0200,
+ NULL,
+ NULL,
+ "2.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+},
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &userstat_info,
+ "TABLE_STATISTICS",
+ "Percona and Sergei Golubchik",
+ "Table Statistics",
+ PLUGIN_LICENSE_GPL,
+ table_stats_init,
+ 0,
+ 0x0200,
+ NULL,
+ NULL,
+ "2.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+},
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &userstat_info,
+ "USER_STATISTICS",
+ "Percona and Sergei Golubchik",
+ "User Statistics",
+ PLUGIN_LICENSE_GPL,
+ user_stats_init,
+ 0,
+ 0x0200,
+ NULL,
+ NULL,
+ "2.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
+
diff --git a/plugin/versioning/CMakeLists.txt b/plugin/versioning/CMakeLists.txt
new file mode 100644
index 00000000..0098dc88
--- /dev/null
+++ b/plugin/versioning/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Copyright (c) 2016, MariaDB corporation. 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
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+MYSQL_ADD_PLUGIN(test_versioning versioning.cc RECOMPILE_FOR_EMBEDDED
+ MODULE_ONLY COMPONENT Test)
diff --git a/plugin/versioning/versioning.cc b/plugin/versioning/versioning.cc
new file mode 100644
index 00000000..6275fadb
--- /dev/null
+++ b/plugin/versioning/versioning.cc
@@ -0,0 +1,206 @@
+/* Copyright (c) 2016, MariaDB corporation. 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
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
+
+#define MYSQL_SERVER 1
+#include <my_global.h>
+#include <mysql_version.h>
+#include <mysqld.h>
+#include <mysql/plugin.h>
+#include "sql_plugin.h" // st_plugin_int
+#include "sql_class.h"
+#include "item.h"
+#include "table.h"
+#include "vers_string.h"
+
+/* System Versioning: TRT_TRX_ID(), TRT_COMMIT_ID(), TRT_BEGIN_TS(), TRT_COMMIT_TS(), TRT_ISO_LEVEL() */
+template <TR_table::field_id_t TRT_FIELD>
+class Create_func_trt : public Create_native_func
+{
+public:
+ virtual Item *create_native(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
+
+ static Create_func_trt<TRT_FIELD> s_singleton;
+
+protected:
+ Create_func_trt<TRT_FIELD>() {}
+ virtual ~Create_func_trt<TRT_FIELD>() {}
+};
+
+template<TR_table::field_id_t TRT_FIELD>
+Create_func_trt<TRT_FIELD> Create_func_trt<TRT_FIELD>::s_singleton;
+
+template <TR_table::field_id_t TRT_FIELD>
+Item*
+Create_func_trt<TRT_FIELD>::create_native(THD *thd, LEX_CSTRING *name,
+ List<Item> *item_list)
+{
+ Item *func= NULL;
+ int arg_count= 0;
+
+ if (item_list != NULL)
+ arg_count= item_list->elements;
+
+ switch (arg_count) {
+ case 1:
+ {
+ Item *param_1= item_list->pop();
+ switch (TRT_FIELD)
+ {
+ case TR_table::FLD_BEGIN_TS:
+ case TR_table::FLD_COMMIT_TS:
+ func= new (thd->mem_root) Item_func_trt_ts(thd, param_1, TRT_FIELD);
+ break;
+ case TR_table::FLD_TRX_ID:
+ case TR_table::FLD_COMMIT_ID:
+ case TR_table::FLD_ISO_LEVEL:
+ func= new (thd->mem_root) Item_func_trt_id(thd, param_1, TRT_FIELD);
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ break;
+ }
+ case 2:
+ {
+ Item *param_1= item_list->pop();
+ Item *param_2= item_list->pop();
+ switch (TRT_FIELD)
+ {
+ case TR_table::FLD_TRX_ID:
+ case TR_table::FLD_COMMIT_ID:
+ func= new (thd->mem_root) Item_func_trt_id(thd, param_1, param_2, TRT_FIELD);
+ break;
+ default:
+ goto error;
+ }
+ break;
+ }
+ error:
+ default:
+ {
+ my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
+ break;
+ }
+ }
+
+ return func;
+};
+
+template <class Item_func_trt_trx_seesX>
+class Create_func_trt_trx_sees : public Create_native_func
+{
+public:
+ virtual Item *create_native(THD *thd, LEX_CSTRING *name, List<Item> *item_list)
+ {
+ Item *func= NULL;
+ int arg_count= 0;
+
+ if (item_list != NULL)
+ arg_count= item_list->elements;
+
+ switch (arg_count) {
+ case 2:
+ {
+ Item *param_1= item_list->pop();
+ Item *param_2= item_list->pop();
+ func= new (thd->mem_root) Item_func_trt_trx_seesX(thd, param_1, param_2);
+ break;
+ }
+ default:
+ my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
+ break;
+ }
+
+ return func;
+ }
+
+ static Create_func_trt_trx_sees<Item_func_trt_trx_seesX> s_singleton;
+
+protected:
+ Create_func_trt_trx_sees<Item_func_trt_trx_seesX>() {}
+ virtual ~Create_func_trt_trx_sees<Item_func_trt_trx_seesX>() {}
+};
+
+template<class X>
+Create_func_trt_trx_sees<X> Create_func_trt_trx_sees<X>::s_singleton;
+
+#define BUILDER(F) & F::s_singleton
+
+static Native_func_registry func_array[] =
+{
+ { { C_STRING_WITH_LEN("TRT_BEGIN_TS") }, BUILDER(Create_func_trt<TR_table::FLD_BEGIN_TS>)},
+ { { C_STRING_WITH_LEN("TRT_COMMIT_ID") }, BUILDER(Create_func_trt<TR_table::FLD_COMMIT_ID>)},
+ { { C_STRING_WITH_LEN("TRT_COMMIT_TS") }, BUILDER(Create_func_trt<TR_table::FLD_COMMIT_TS>)},
+ { { C_STRING_WITH_LEN("TRT_ISO_LEVEL") }, BUILDER(Create_func_trt<TR_table::FLD_ISO_LEVEL>)},
+ { { C_STRING_WITH_LEN("TRT_TRX_ID") }, BUILDER(Create_func_trt<TR_table::FLD_TRX_ID>)},
+ { { C_STRING_WITH_LEN("TRT_TRX_SEES") }, BUILDER(Create_func_trt_trx_sees<Item_func_trt_trx_sees>)},
+ { { C_STRING_WITH_LEN("TRT_TRX_SEES_EQ") }, BUILDER(Create_func_trt_trx_sees<Item_func_trt_trx_sees_eq>)},
+ { {0, 0}, NULL}
+};
+
+
+/*
+ Disable __attribute__() on non-gcc compilers.
+*/
+#if !defined(__attribute__) && !defined(__GNUC__)
+#define __attribute__(A)
+#endif
+
+static int versioning_plugin_init(void *p __attribute__ ((unused)))
+{
+ DBUG_ENTER("versioning_plugin_init");
+ // No need in locking since we so far single-threaded
+ int res= item_create_append(func_array);
+ if (res)
+ {
+ my_message(ER_PLUGIN_IS_NOT_LOADED, "Can't append function array" , MYF(0));
+ DBUG_RETURN(res);
+ }
+
+ DBUG_RETURN(0);
+}
+
+static int versioning_plugin_deinit(void *p __attribute__ ((unused)))
+{
+ DBUG_ENTER("versioning_plugin_deinit");
+ (void) item_create_remove(func_array);
+ DBUG_RETURN(0);
+}
+
+struct st_mysql_daemon versioning_plugin=
+{ MYSQL_REPLICATION_INTERFACE_VERSION };
+
+/*
+ Plugin library descriptor
+*/
+
+maria_declare_plugin(versioning)
+{
+ MYSQL_REPLICATION_PLUGIN, // initialized after MYSQL_STORAGE_ENGINE_PLUGIN
+ &versioning_plugin,
+ "test_versioning",
+ "MariaDB Corp",
+ "System Vesioning testing features",
+ PLUGIN_LICENSE_GPL,
+ versioning_plugin_init, /* Plugin Init */
+ versioning_plugin_deinit, /* Plugin Deinit */
+ 0x0100 /* 1.0 */,
+ NULL, /* status variables */
+ NULL, /* system variables */
+ "1.0", /* string version */
+ MariaDB_PLUGIN_MATURITY_EXPERIMENTAL
+}
+maria_declare_plugin_end;
diff --git a/plugin/win_auth_client/CMakeLists.txt b/plugin/win_auth_client/CMakeLists.txt
new file mode 100644
index 00000000..46f837e5
--- /dev/null
+++ b/plugin/win_auth_client/CMakeLists.txt
@@ -0,0 +1,34 @@
+# Copyright (c) 2011, 2013, 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
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
+
+IF(WIN32)
+ #
+ # Configuration for building Windows Authentication Plugin (client-side)
+ #
+
+ ADD_DEFINITIONS(-DSECURITY_WIN32)
+ ADD_DEFINITIONS(-DDEBUG_ERRROR_LOG) # no error logging in production builds
+ #ADD_DEFINITIONS(-DWINAUTH_USE_DBUG_LIB) # it is OK to use dbug library in statically
+ # # linked plugin
+
+ SET(HEADERS common.h handshake.h)
+ SET(PLUGIN_SOURCES plugin_client.cc handshake_client.cc
+ log_client.cc common.cc handshake.cc)
+
+ MYSQL_ADD_PLUGIN(authentication_windows_client ${PLUGIN_SOURCES} ${HEADERS}
+ LINK_LIBRARIES Secur32
+ MODULE_ONLY COMPONENT ClientPlugins CLIENT)
+
+ENDIF(WIN32)
diff --git a/plugin/win_auth_client/common.cc b/plugin/win_auth_client/common.cc
new file mode 100644
index 00000000..8b731925
--- /dev/null
+++ b/plugin/win_auth_client/common.cc
@@ -0,0 +1,510 @@
+/* Copyright (c) 2011, 2019, 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
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "common.h"
+#include <sddl.h> // for ConvertSidToStringSid()
+#include <secext.h> // for GetUserNameEx()
+
+
+template <> void error_log_print<error_log_level::INFO>(const char *fmt, ...);
+template <> void error_log_print<error_log_level::WARNING>(const char *fmt, ...);
+template <> void error_log_print<error_log_level::ERROR>(const char *fmt, ...);
+
+/**
+ Option indicating desired level of logging. Values:
+
+ 0 - no logging
+ 1 - log only error messages
+ 2 - additionally log warnings
+ 3 - additionally log info notes
+ 4 - also log debug messages
+
+ Value of this option should be taken into account in the
+ implementation of error_log_vprint() function (see
+ log_client.cc).
+
+ Note: No error or debug messages are logged in production code
+ (see logging macros in common.h).
+*/
+int opt_auth_win_log_level= 2;
+
+
+/** Connection class **************************************************/
+
+/**
+ Create connection out of an active MYSQL_PLUGIN_VIO object.
+
+ @param[in] vio pointer to a @c MYSQL_PLUGIN_VIO object used for
+ connection - it can not be NULL
+*/
+
+Connection::Connection(MYSQL_PLUGIN_VIO *vio): m_vio(vio), m_error(0)
+{
+ DBUG_ASSERT(vio);
+}
+
+
+/**
+ Write data to the connection.
+
+ @param[in] blob data to be written
+
+ @return 0 on success, VIO error code on failure.
+
+ @note In case of error, VIO error code is stored in the connection object
+ and can be obtained with @c error() method.
+*/
+
+int Connection::write(const Blob &blob)
+{
+ m_error= m_vio->write_packet(m_vio, blob.ptr(), (int)blob.len());
+
+#ifndef DBUG_OFF
+ if (m_error)
+ DBUG_PRINT("error", ("vio write error %d", m_error));
+#endif
+
+ return m_error;
+}
+
+
+/**
+ Read data from connection.
+
+ @return A Blob containing read packet or null Blob in case of error.
+
+ @note In case of error, VIO error code is stored in the connection object
+ and can be obtained with @c error() method.
+*/
+
+Blob Connection::read()
+{
+ unsigned char *ptr;
+ int len= m_vio->read_packet(m_vio, &ptr);
+
+ if (len < 0)
+ {
+ m_error= true;
+ return Blob();
+ }
+
+ return Blob(ptr, len);
+}
+
+
+/** Sid class *****************************************************/
+
+
+/**
+ Create Sid object corresponding to a given account name.
+
+ @param[in] account_name name of a Windows account
+
+ The account name can be in any form accepted by @c LookupAccountName()
+ function.
+
+ @note In case of errors created object is invalid and its @c is_valid()
+ method returns @c false.
+*/
+
+Sid::Sid(const wchar_t *account_name): m_data(NULL)
+#ifndef DBUG_OFF
+, m_as_string(NULL)
+#endif
+{
+ DWORD sid_size= 0, domain_size= 0;
+ bool success;
+
+ // Determine required buffer sizes
+
+ success= LookupAccountNameW(NULL, account_name, NULL, &sid_size,
+ NULL, &domain_size, &m_type);
+
+ if (!success && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ {
+#ifndef DBUG_OFF
+ Error_message_buf error_buf;
+ DBUG_PRINT("error", ("Could not determine SID buffer size, "
+ "LookupAccountName() failed with error %X (%s)",
+ GetLastError(), get_last_error_message(error_buf)));
+#endif
+ return;
+ }
+
+ // Query for SID (domain is ignored)
+
+ wchar_t *domain= new wchar_t[domain_size];
+ m_data= (TOKEN_USER*) new BYTE[sid_size + sizeof(TOKEN_USER)];
+ m_data->User.Sid= (BYTE*)m_data + sizeof(TOKEN_USER);
+
+ success= LookupAccountNameW(NULL, account_name,
+ m_data->User.Sid, &sid_size,
+ domain, &domain_size,
+ &m_type);
+
+ if (!success || !is_valid())
+ {
+#ifndef DBUG_OFF
+ Error_message_buf error_buf;
+ DBUG_PRINT("error", ("Could not determine SID of '%S', "
+ "LookupAccountName() failed with error %X (%s)",
+ account_name, GetLastError(),
+ get_last_error_message(error_buf)));
+#endif
+ goto fail;
+ }
+
+ goto end;
+
+fail:
+ if (m_data)
+ delete [] m_data;
+ m_data= NULL;
+
+end:
+ if (domain)
+ delete [] domain;
+}
+
+
+/**
+ Create Sid object corresponding to a given security token.
+
+ @param[in] token security token of a Windows account
+
+ @note In case of errors created object is invalid and its @c is_valid()
+ method returns @c false.
+*/
+
+Sid::Sid(HANDLE token): m_data(NULL)
+#ifndef DBUG_OFF
+, m_as_string(NULL)
+#endif
+{
+ DWORD req_size= 0;
+ bool success;
+
+ // Determine required buffer size
+
+ success= GetTokenInformation(token, TokenUser, NULL, 0, &req_size);
+ if (!success && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ {
+#ifndef DBUG_OFF
+ Error_message_buf error_buf;
+ DBUG_PRINT("error", ("Could not determine SID buffer size, "
+ "GetTokenInformation() failed with error %X (%s)",
+ GetLastError(), get_last_error_message(error_buf)));
+#endif
+ return;
+ }
+
+ m_data= (TOKEN_USER*) new BYTE[req_size];
+ success= GetTokenInformation(token, TokenUser, m_data, req_size, &req_size);
+
+ if (!success || !is_valid())
+ {
+ delete [] m_data;
+ m_data= NULL;
+#ifndef DBUG_OFF
+ if (!success)
+ {
+ Error_message_buf error_buf;
+ DBUG_PRINT("error", ("Could not read SID from security token, "
+ "GetTokenInformation() failed with error %X (%s)",
+ GetLastError(), get_last_error_message(error_buf)));
+ }
+#endif
+ }
+}
+
+
+Sid::~Sid()
+{
+ if (m_data)
+ delete [] m_data;
+#ifndef DBUG_OFF
+ if (m_as_string)
+ LocalFree(m_as_string);
+#endif
+}
+
+/// Check if Sid object is valid.
+bool Sid::is_valid(void) const
+{
+ return m_data && m_data->User.Sid && IsValidSid(m_data->User.Sid);
+}
+
+
+#ifndef DBUG_OFF
+
+/**
+ Produces string representation of the SID.
+
+ @return String representation of the SID or NULL in case of errors.
+
+ @note Memory allocated for the string is automatically freed in Sid's
+ destructor.
+*/
+
+const char* Sid::as_string()
+{
+ if (!m_data)
+ return NULL;
+
+ if (!m_as_string)
+ {
+ bool success= ConvertSidToStringSid(m_data->User.Sid, &m_as_string);
+
+ if (!success)
+ {
+#ifndef DBUG_OFF
+ Error_message_buf error_buf;
+ DBUG_PRINT("error", ("Could not get textual representation of a SID, "
+ "ConvertSidToStringSid() failed with error %X (%s)",
+ GetLastError(), get_last_error_message(error_buf)));
+#endif
+ m_as_string= NULL;
+ return NULL;
+ }
+ }
+
+ return m_as_string;
+}
+
+#endif
+
+
+bool Sid::operator ==(const Sid &other)
+{
+ if (!is_valid() || !other.is_valid())
+ return false;
+
+ return EqualSid(m_data->User.Sid, other.m_data->User.Sid);
+}
+
+
+/** Generating User Principal Name *************************/
+
+/**
+ Call Windows API functions to get UPN of the current user and store it
+ in internal buffer.
+*/
+
+UPN::UPN(): m_buf(NULL)
+{
+ wchar_t buf1[MAX_SERVICE_NAME_LENGTH];
+
+ // First we try to use GetUserNameEx.
+
+ m_len= sizeof(buf1)/sizeof(wchar_t);
+
+ if (!GetUserNameExW(NameUserPrincipal, buf1, (PULONG)&m_len))
+ {
+ if (GetLastError())
+ {
+#ifndef DBUG_OFF
+ Error_message_buf error_buf;
+ DBUG_PRINT("note", ("When determining UPN"
+ ", GetUserNameEx() failed with error %X (%s)",
+ GetLastError(), get_last_error_message(error_buf)));
+#endif
+ if (ERROR_MORE_DATA == GetLastError())
+ ERROR_LOG(INFO, ("Buffer overrun when determining UPN:"
+ " need %ul characters but have %ul",
+ m_len, sizeof(buf1)/sizeof(WCHAR)));
+ }
+
+ m_len= 0; // m_len == 0 indicates invalid UPN
+ return;
+ }
+
+ /*
+ UPN is stored in buf1 in wide-char format - convert it to utf8
+ for sending over network.
+ */
+
+ m_buf= wchar_to_utf8(buf1, &m_len);
+
+ if(!m_buf)
+ ERROR_LOG(ERROR, ("Failed to convert UPN to utf8"));
+
+ // Note: possible error would be indicated by the fact that m_buf is NULL.
+ return;
+}
+
+
+UPN::~UPN()
+{
+ if (m_buf)
+ free(m_buf);
+}
+
+
+/**
+ Convert a wide-char string to utf8 representation.
+
+ @param[in] string null-terminated wide-char string to be converted
+ @param[in,out] len length of the string to be converted or 0; on
+ return length (in bytes, excluding terminating
+ null character) of the converted string
+
+ If len is 0 then the length of the string will be computed by this function.
+
+ @return Pointer to a buffer containing utf8 representation or NULL in
+ case of error.
+
+ @note The returned buffer must be freed with @c free() call.
+*/
+
+char* wchar_to_utf8(const wchar_t *string, size_t *len)
+{
+ char *buf= NULL;
+ size_t str_len= len && *len ? *len : wcslen(string);
+
+ /*
+ A conversion from utf8 to wchar_t will never take more than 3 bytes per
+ character, so a buffer of length 3 * str_len should be sufficient.
+ We check that assumption with an assertion later.
+ */
+
+ size_t buf_len= 3 * str_len;
+
+ buf= (char*)malloc(buf_len + 1);
+ if (!buf)
+ {
+ DBUG_PRINT("error",("Out of memory when converting string '%S' to utf8",
+ string));
+ return NULL;
+ }
+
+ int res= WideCharToMultiByte(CP_UTF8, // convert to UTF-8
+ 0, // conversion flags
+ string, // input buffer
+ (int)str_len, // its length
+ buf, (int)buf_len, // output buffer and its size
+ NULL, NULL); // default character (not used)
+
+ if (res)
+ {
+ buf[res]= '\0';
+ if (len)
+ *len= res;
+ return buf;
+ }
+
+ // res is 0 which indicates error
+
+#ifndef DBUG_OFF
+ Error_message_buf error_buf;
+ DBUG_PRINT("error", ("Could not convert string '%S' to utf8"
+ ", WideCharToMultiByte() failed with error %X (%s)",
+ string, GetLastError(),
+ get_last_error_message(error_buf)));
+#endif
+
+ // Let's check our assumption about sufficient buffer size
+ DBUG_ASSERT(ERROR_INSUFFICIENT_BUFFER != GetLastError());
+
+ return NULL;
+}
+
+
+/**
+ Convert an utf8 string to a wide-char string.
+
+ @param[in] string null-terminated utf8 string to be converted
+ @param[in,out] len length of the string to be converted or 0; on
+ return length (in chars) of the converted string
+
+ If len is 0 then the length of the string will be computed by this function.
+
+ @return Pointer to a buffer containing wide-char representation or NULL in
+ case of error.
+
+ @note The returned buffer must be freed with @c free() call.
+*/
+
+wchar_t* utf8_to_wchar(const char *string, size_t *len)
+{
+ size_t buf_len;
+
+ /*
+ Note: length (in bytes) of an utf8 string is always bigger than the
+ number of characters in this string. Hence a buffer of size len will
+ be sufficient. We add 1 for the terminating null character.
+ */
+
+ buf_len= len && *len ? *len : strlen(string);
+ wchar_t *buf= (wchar_t*)malloc((buf_len+1)*sizeof(wchar_t));
+
+ if (!buf)
+ {
+ DBUG_PRINT("error",("Out of memory when converting utf8 string '%s'"
+ " to wide-char representation", string));
+ return NULL;
+ }
+
+ size_t res;
+ res= MultiByteToWideChar(CP_UTF8, // convert from UTF-8
+ 0, // conversion flags
+ string, // input buffer
+ (int)buf_len, // its size
+ buf, (int)buf_len); // output buffer and its size
+ if (res)
+ {
+ buf[res]= '\0';
+ if (len)
+ *len= res;
+ return buf;
+ }
+
+ // error in MultiByteToWideChar()
+
+#ifndef DBUG_OFF
+ Error_message_buf error_buf;
+ DBUG_PRINT("error", ("Could not convert UPN from UTF-8"
+ ", MultiByteToWideChar() failed with error %X (%s)",
+ GetLastError(), get_last_error_message(error_buf)));
+#endif
+
+ // Let's check our assumption about sufficient buffer size
+ DBUG_ASSERT(ERROR_INSUFFICIENT_BUFFER != GetLastError());
+
+ return NULL;
+}
+
+
+/** Error handling ****************************************************/
+
+
+/**
+ Returns error message corresponding to the last Windows error given
+ by GetLastError().
+
+ @note Error message is overwritten by next call to
+ @c get_last_error_message().
+*/
+
+const char* get_last_error_message(Error_message_buf buf)
+{
+ int error= GetLastError();
+
+ buf[0]= '\0';
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR)buf, ERRMSG_BUFSIZE , NULL );
+
+ return buf;
+}
diff --git a/plugin/win_auth_client/common.h b/plugin/win_auth_client/common.h
new file mode 100644
index 00000000..8aeb1cd2
--- /dev/null
+++ b/plugin/win_auth_client/common.h
@@ -0,0 +1,324 @@
+/* Copyright (c) 2011, 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
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#ifndef COMMON_H
+#define COMMON_H
+
+#include <my_global.h>
+#include <windows.h>
+#include <sspi.h> // for CtxtHandle
+#include <mysql/plugin_auth.h> // for MYSQL_PLUGIN_VIO
+
+/// Maximum length of the target service name.
+#define MAX_SERVICE_NAME_LENGTH 1024
+
+
+/** Debugging and error reporting infrastructure ***************************/
+
+/*
+ Note: We use plugin local logging and error reporting mechanisms until
+ WL#2940 (plugin service: error reporting) is available.
+*/
+
+#undef INFO
+#undef WARNING
+#undef ERROR
+
+struct error_log_level
+{
+ typedef enum {INFO, WARNING, ERROR} type;
+};
+
+extern "C" int opt_auth_win_log_level;
+unsigned int get_log_level(void);
+void set_log_level(unsigned int);
+
+
+/*
+ If DEBUG_ERROR_LOG is defined then error logging happens only
+ in debug-copiled code. Otherwise ERROR_LOG() expands to
+ error_log_print() even in production code.
+
+ Note: Macro ERROR_LOG() can use printf-like format string like this:
+
+ ERROR_LOG(Level, ("format string", args));
+
+ The implementation should handle it correctly. Currently it is passed
+ to fprintf() (see error_log_vprint() function).
+*/
+
+#if defined(DEBUG_ERROR_LOG) && defined(DBUG_OFF)
+#define ERROR_LOG(Level, Msg) do {} while (0)
+#else
+#define ERROR_LOG(Level, Msg) error_log_print< error_log_level::Level > Msg
+#endif
+
+
+void error_log_vprint(error_log_level::type level,
+ const char *fmt, va_list args);
+
+template <error_log_level::type Level>
+void error_log_print(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ error_log_vprint(Level, fmt, args);
+ va_end(args);
+}
+#define ERRMSG_BUFSIZE 1024
+typedef char Error_message_buf[ERRMSG_BUFSIZE];
+const char* get_last_error_message(Error_message_buf);
+
+
+/*
+ Internal implementation of debug message printing which does not use
+ dbug library. This is invoked via macro:
+
+ DBUG_PRINT_DO(Keyword, ("format string", args));
+
+ This is supposed to be used as an implementation of DBUG_PRINT() macro,
+ unless the dbug library implementation is used or debug messages are disabled.
+*/
+
+#ifndef DBUG_OFF
+
+#define DBUG_PRINT_DO(Keyword, Msg) \
+ do { \
+ if (4 > get_log_level()) break; \
+ fprintf(stderr, "winauth: %s: ", Keyword); \
+ debug_msg Msg; \
+ } while (0)
+
+inline
+void debug_msg(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ fputc('\n', stderr);
+ fflush(stderr);
+ va_end(args);
+}
+
+#else
+#define DBUG_PRINT_DO(K, M) do {} while (0)
+#endif
+
+
+#ifndef WINAUTH_USE_DBUG_LIB
+
+#undef DBUG_PRINT
+#define DBUG_PRINT(Keyword, Msg) DBUG_PRINT_DO(Keyword, Msg)
+
+/*
+ Redefine few more debug macros to make sure that no symbols from
+ dbug library are used.
+*/
+
+#undef DBUG_ENTER
+#define DBUG_ENTER(X) do {} while (0)
+
+#undef DBUG_RETURN
+#define DBUG_RETURN(X) return (X)
+
+#undef DBUG_ASSERT
+#ifndef DBUG_OFF
+#define DBUG_ASSERT(X) assert (X)
+#else
+#define DBUG_ASSERT(X) do {} while (0)
+#endif
+
+#undef DBUG_DUMP
+#define DBUG_DUMP(A,B,C) do {} while (0)
+
+#endif
+
+
+/** Blob class *************************************************************/
+
+typedef unsigned char byte;
+
+/**
+ Class representing a region of memory (e.g., a string or binary buffer).
+
+ @note This class does not allocate memory. It merely describes a region
+ of memory which must be allocated externally (if it is dynamic memory).
+*/
+
+class Blob
+{
+ byte *m_ptr; ///< Pointer to the first byte of the memory region.
+ size_t m_len; ///< Length of the memory region.
+
+public:
+
+ Blob(): m_ptr(NULL), m_len(0)
+ {}
+
+ Blob(const byte *ptr, const size_t len)
+ : m_ptr(const_cast<byte*>(ptr)), m_len(len)
+ {}
+
+ Blob(const char *str): m_ptr((byte*)str)
+ {
+ m_len= strlen(str);
+ }
+
+ byte* ptr() const
+ {
+ return m_ptr;
+ }
+
+ size_t len() const
+ {
+ return m_len;
+ }
+
+ byte& operator[](unsigned pos) const
+ {
+ static byte out_of_range= 0; // alas, no exceptions...
+ return pos < len() ? m_ptr[pos] : out_of_range;
+ }
+
+ bool is_null() const
+ {
+ return m_ptr == NULL;
+ }
+
+ void trim(size_t l)
+ {
+ m_len= l;
+ }
+};
+
+
+/** Connection class *******************************************************/
+
+/**
+ Convenience wrapper around MYSQL_PLUGIN_VIO object providing basic
+ read/write operations.
+*/
+
+class Connection
+{
+ MYSQL_PLUGIN_VIO *m_vio; ///< Pointer to @c MYSQL_PLUGIN_VIO structure.
+
+ /**
+ If non-zero, indicates that connection is broken. If this has happened
+ because of failed operation, stores non-zero error code from that failure.
+ */
+ int m_error;
+
+public:
+
+ Connection(MYSQL_PLUGIN_VIO *vio);
+ int write(const Blob&);
+ Blob read();
+
+ int error() const
+ {
+ return m_error;
+ }
+};
+
+
+/** Sid class **************************************************************/
+
+/**
+ Class for storing and manipulating Windows security identifiers (SIDs).
+*/
+
+class Sid
+{
+ TOKEN_USER *m_data; ///< Pointer to structure holding identifier's data.
+ SID_NAME_USE m_type; ///< Type of identified entity.
+
+public:
+
+ Sid(const wchar_t*);
+ Sid(HANDLE sec_token);
+ ~Sid();
+
+ bool is_valid(void) const;
+
+ bool is_group(void) const
+ {
+ return m_type == SidTypeGroup
+ || m_type == SidTypeWellKnownGroup
+ || m_type == SidTypeAlias;
+ }
+
+ bool is_user(void) const
+ {
+ return m_type == SidTypeUser;
+ }
+
+ bool operator==(const Sid&);
+
+ operator PSID() const
+ {
+ return (PSID)m_data->User.Sid;
+ }
+
+#ifndef DBUG_OFF
+
+private:
+ char *m_as_string; ///< Cached string representation of the SID.
+public:
+ const char* as_string();
+
+#endif
+};
+
+
+/** UPN class **************************************************************/
+
+/**
+ An object of this class obtains and stores User Principal Name of the
+ account under which current process is running.
+*/
+
+class UPN
+{
+ char *m_buf; ///< Pointer to UPN in utf8 representation.
+ size_t m_len; ///< Length of the name.
+
+public:
+
+ UPN();
+ ~UPN();
+
+ bool is_valid() const
+ {
+ return m_len > 0;
+ }
+
+ const Blob as_blob() const
+ {
+ return m_len ? Blob((byte*)m_buf, m_len) : Blob();
+ }
+
+ const char* as_string() const
+ {
+ return (const char*)m_buf;
+ }
+
+};
+
+
+char* wchar_to_utf8(const wchar_t*, size_t*);
+wchar_t* utf8_to_wchar(const char*, size_t*);
+
+#endif
diff --git a/plugin/win_auth_client/handshake.cc b/plugin/win_auth_client/handshake.cc
new file mode 100644
index 00000000..cd63ee26
--- /dev/null
+++ b/plugin/win_auth_client/handshake.cc
@@ -0,0 +1,289 @@
+/* Copyright (c) 2011, 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
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "handshake.h"
+
+
+/** Handshake class implementation **********************************/
+
+/**
+ Create common part of handshake context.
+
+ @param[in] ssp name of the SSP (Security Service Provider) to
+ be used for authentication
+ @param[in] side is this handshake object used for server- or
+ client-side handshake
+
+ Prepare for handshake using the @c ssp security module. We use
+ "Negotiate" which picks best available module. Parameter @c side
+ tells if this is preparing for server or client side authentication
+ and is used to prepare appropriate credentials.
+*/
+
+Handshake::Handshake(const char *ssp, side_t side)
+: m_atts(0L), m_error(0), m_complete(FALSE),
+ m_have_credentials(false), m_have_sec_context(false)
+#ifndef DBUG_OFF
+ , m_ssp_info(NULL)
+#endif
+{
+ SECURITY_STATUS ret;
+
+ // Obtain credentials for the authentication handshake.
+
+ ret= AcquireCredentialsHandle(NULL, (SEC_CHAR*)ssp,
+ side == SERVER ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND,
+ NULL, NULL, NULL, NULL, &m_cred, &m_expire);
+
+ if (ret != SEC_E_OK)
+ {
+ DBUG_PRINT("error", ("AcqireCredentialsHandle() failed"
+ " with error %X", ret));
+ ERROR_LOG(ERROR, ("Could not obtain local credentials"
+ " required for authentication"));
+ m_error= ret;
+ }
+
+ m_have_credentials= true;
+}
+
+
+Handshake::~Handshake()
+{
+ if (m_have_credentials)
+ FreeCredentialsHandle(&m_cred);
+ if (m_have_sec_context)
+ DeleteSecurityContext(&m_sctx);
+ m_output.free();
+
+#ifndef DBUG_OFF
+ if (m_ssp_info)
+ FreeContextBuffer(m_ssp_info);
+#endif
+}
+
+
+/**
+ Read and process data packets from the other end of a connection.
+
+ @param[IN] con a connection to read packets from
+
+ Packets are read and processed until authentication handshake is
+ complete. It is assumed that the peer will send at least one packet.
+ Packets are processed with @c process_data() method. If new data is
+ generated during packet processing, this data is sent to the peer and
+ another round of packet exchange starts.
+
+ @return 0 on success.
+
+ @note In case of error, appropriate error message is logged.
+*/
+int Handshake::packet_processing_loop()
+{
+ m_round= 0;
+
+ do {
+ ++m_round;
+ // Read packet send by the peer
+
+ DBUG_PRINT("info", ("Waiting for packet"));
+ Blob packet= read_packet();
+ if (error())
+ {
+ ERROR_LOG(ERROR, ("Error reading packet in round %d", m_round));
+ return 1;
+ }
+ DBUG_PRINT("info", ("Got packet of length %d", packet.len()));
+
+ /*
+ Process received data, possibly generating new data to be sent.
+ */
+
+ Blob new_data= process_data(packet);
+
+ if (error())
+ {
+ ERROR_LOG(ERROR, ("Error processing packet in round %d", m_round));
+ return 1;
+ }
+
+ /*
+ If new data has been generated, send it to the peer. Otherwise
+ handshake must be completed.
+ */
+
+ if (!new_data.is_null())
+ {
+ DBUG_PRINT("info", ("Round %d started", m_round));
+
+ DBUG_PRINT("info", ("Sending packet of length %d", new_data.len()));
+ int ret= write_packet(new_data);
+ if (ret)
+ {
+ ERROR_LOG(ERROR, ("Error writing packet in round %d", m_round));
+ return 1;
+ }
+ DBUG_PRINT("info", ("Data sent"));
+ }
+ else if (!is_complete())
+ {
+ ERROR_LOG(ERROR, ("No data to send in round %d"
+ " but handshake is not complete", m_round));
+ return 1;
+ }
+
+ /*
+ To protect against malicious clients, break handshake exchange if
+ too many rounds.
+ */
+
+ if (m_round > MAX_HANDSHAKE_ROUNDS)
+ {
+ ERROR_LOG(ERROR, ("Authentication handshake could not be completed"
+ " after %d rounds", m_round));
+ return 1;
+ }
+
+ } while(!is_complete());
+
+ ERROR_LOG(INFO, ("Handshake completed after %d rounds", m_round));
+ return 0;
+}
+
+
+#ifndef DBUG_OFF
+
+/**
+ Get name of the security package which was used in authentication.
+
+ This method should be called only after handshake was completed. It is
+ available only in debug builds.
+
+ @return Name of security package or NULL if it can not be obtained.
+*/
+
+const char* Handshake::ssp_name()
+{
+ if (!m_ssp_info && m_complete)
+ {
+ SecPkgContext_PackageInfo pinfo;
+
+ int ret= QueryContextAttributes(&m_sctx, SECPKG_ATTR_PACKAGE_INFO, &pinfo);
+
+ if (SEC_E_OK == ret)
+ {
+ m_ssp_info= pinfo.PackageInfo;
+ }
+ else
+ DBUG_PRINT("error",
+ ("Could not obtain SSP info from authentication context"
+ ", QueryContextAttributes() failed with error %X", ret));
+ }
+
+ return m_ssp_info ? m_ssp_info->Name : NULL;
+}
+
+#endif
+
+
+/**
+ Process result of @c {Initialize,Accept}SecurityContext() function.
+
+ @param[in] ret return code from @c {Initialize,Accept}SecurityContext()
+ function
+
+ This function analyses return value of Windows
+ @c {Initialize,Accept}SecurityContext() function. A call to
+ @c CompleteAuthToken() is done if requested. If authentication is complete,
+ this fact is marked in the internal state of the Handshake object.
+ If errors are detected the object is moved to error state.
+
+ @return True if error has been detected.
+*/
+
+bool Handshake::process_result(int ret)
+{
+ /*
+ First check for errors and set the m_complete flag if the result
+ indicates that handshake is complete.
+ */
+
+ switch (ret)
+ {
+ case SEC_E_OK:
+ case SEC_I_COMPLETE_NEEDED:
+ // Handshake completed
+ m_complete= true;
+ break;
+
+ case SEC_I_CONTINUE_NEEDED:
+ case SEC_I_COMPLETE_AND_CONTINUE:
+ break;
+
+ default:
+ m_error= ret;
+ return true;
+ }
+
+ m_have_sec_context= true;
+
+ /*
+ If the result indicates a need for this, complete the authentication
+ token.
+ */
+
+ switch (ret)
+ {
+ case SEC_I_COMPLETE_NEEDED:
+ case SEC_I_COMPLETE_AND_CONTINUE:
+ ret= CompleteAuthToken(&m_sctx, &m_output);
+ if (ret != 0)
+ {
+ DBUG_PRINT("error", ("CompleteAuthToken() failed with error %X", ret));
+ m_error= ret;
+ return true;
+ }
+ default:
+ break;
+ }
+
+ return false;
+}
+
+
+/** Security_buffer class implementation **********************************/
+
+
+Security_buffer::Security_buffer(const Blob &blob): m_allocated(false)
+{
+ init(blob.ptr(), blob.len());
+}
+
+
+Security_buffer::Security_buffer(): m_allocated(true)
+{
+ init(NULL, 0);
+}
+
+
+void Security_buffer::free(void)
+{
+ if (!m_allocated)
+ return;
+ if (!ptr())
+ return;
+ FreeContextBuffer(ptr());
+ m_allocated= false;
+}
diff --git a/plugin/win_auth_client/handshake.h b/plugin/win_auth_client/handshake.h
new file mode 100644
index 00000000..2eac0afb
--- /dev/null
+++ b/plugin/win_auth_client/handshake.h
@@ -0,0 +1,181 @@
+/* Copyright (c) 2011, 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
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#ifndef HANDSHAKE_H
+#define HANDSHAKE_H
+
+#include "common.h"
+
+/**
+ Name of the SSP (Security Support Provider) to be used for authentication.
+
+ We use "Negotiate" which will find the most secure SSP which can be used
+ and redirect to that SSP.
+*/
+#define SSP_NAME "Negotiate"
+
+/**
+ Maximal number of rounds in authentication handshake.
+
+ Server will interrupt authentication handshake with error if client's
+ identity can not be determined within this many rounds.
+*/
+#define MAX_HANDSHAKE_ROUNDS 50
+
+
+/// Convenience wrapper around @c SecBufferDesc.
+
+class Security_buffer: public SecBufferDesc
+{
+ SecBuffer m_buf; ///< A @c SecBuffer instance.
+
+ void init(byte *ptr, size_t len)
+ {
+ ulVersion= 0;
+ cBuffers= 1;
+ pBuffers= &m_buf;
+
+ m_buf.BufferType= SECBUFFER_TOKEN;
+ m_buf.pvBuffer= ptr;
+ m_buf.cbBuffer= (ULONG)len;
+ }
+
+ /// If @c false, no deallocation will be done in the destructor.
+ bool m_allocated;
+
+ public:
+
+ Security_buffer(const Blob&);
+ Security_buffer();
+
+ ~Security_buffer()
+ {
+ free();
+ }
+
+ byte* ptr() const
+ {
+ return (byte*)m_buf.pvBuffer;
+ }
+
+ size_t len() const
+ {
+ return m_buf.cbBuffer;
+ }
+
+ bool is_valid() const
+ {
+ return ptr() != NULL;
+ }
+
+ const Blob as_blob() const
+ {
+ return Blob(ptr(), len());
+ }
+
+ void free(void);
+};
+
+
+/// Common base for Handshake_{server,client}.
+
+class Handshake
+{
+public:
+
+ typedef enum {CLIENT, SERVER} side_t;
+
+ Handshake(const char *ssp, side_t side);
+ virtual ~Handshake();
+
+ int packet_processing_loop();
+
+ bool virtual is_complete() const
+ {
+ return m_complete;
+ }
+
+ int error() const
+ {
+ return m_error;
+ }
+
+protected:
+
+ /// Security context object created during the handshake.
+ CtxtHandle m_sctx;
+
+ /// Credentials of the principal performing this handshake.
+ CredHandle m_cred;
+
+ /// Stores expiry date of the created security context.
+ TimeStamp m_expire;
+
+ /// Stores attributes of the created security context.
+ ULONG m_atts;
+
+ /**
+ Round of the handshake (starting from round 1). One round
+ consist of reading packet from the other side, processing it and
+ optionally sending a reply (see @c packet_processing_loop()).
+ */
+ unsigned int m_round;
+
+ /// If non-zero, stores error code of the last failed operation.
+ int m_error;
+
+ /// @c true when handshake is complete.
+ bool m_complete;
+
+ /// @c true when the principal credentials has been determined.
+ bool m_have_credentials;
+
+ /// @c true when the security context has been created.
+ bool m_have_sec_context;
+
+ /// Buffer for data to be send to the other side.
+ Security_buffer m_output;
+
+ bool process_result(int);
+
+ /**
+ This method is used inside @c packet_processing_loop to process
+ data packets received from the other end.
+
+ @param[IN] data data to be processed
+
+ @return A blob with data to be sent to the other end or null blob if
+ no more data needs to be exchanged.
+ */
+ virtual Blob process_data(const Blob &data) =0;
+
+ /// Read packet from the other end.
+ virtual Blob read_packet() =0;
+
+ /// Write packet to the other end.
+ virtual int write_packet(Blob &data) =0;
+
+#ifndef DBUG_OFF
+
+private:
+ SecPkgInfo *m_ssp_info;
+public:
+ const char* ssp_name();
+
+#endif
+};
+
+
+#endif
diff --git a/plugin/win_auth_client/handshake_client.cc b/plugin/win_auth_client/handshake_client.cc
new file mode 100644
index 00000000..28a228cc
--- /dev/null
+++ b/plugin/win_auth_client/handshake_client.cc
@@ -0,0 +1,393 @@
+/* Copyright (c) 2011, 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
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "handshake.h"
+
+#include <mysql.h> // for MYSQL structure
+
+
+/// Client-side context for authentication handshake
+
+class Handshake_client: public Handshake
+{
+ /**
+ Name of the server's service for which we authenticate.
+
+ The service name is sent by server in the initial packet. If no
+ service name is used, this member is @c NULL.
+ */
+ SEC_WCHAR *m_service_name;
+
+ /// Buffer for storing service name obtained from server.
+ SEC_WCHAR m_service_name_buf[MAX_SERVICE_NAME_LENGTH];
+
+ Connection &m_con;
+
+public:
+
+ Handshake_client(Connection &con, const char *target, size_t len);
+ ~Handshake_client();
+
+ Blob first_packet();
+ Blob process_data(const Blob&);
+
+ Blob read_packet();
+ int write_packet(Blob &data);
+};
+
+
+/**
+ Create authentication handshake context for client.
+
+ @param con connection for communication with the peer
+ @param target name of the target service with which we will authenticate
+ (can be NULL if not used)
+
+ Some security packages (like Kerberos) require providing explicit name
+ of the service with which a client wants to authenticate. The server-side
+ authentication plugin sends this name in the greeting packet
+ (see @c win_auth_handshake_{server,client}() functions).
+*/
+
+Handshake_client::Handshake_client(Connection &con,
+ const char *target, size_t len)
+: Handshake(SSP_NAME, CLIENT), m_service_name(NULL), m_con(con)
+{
+ if (!target || 0 == len)
+ return;
+
+ // Convert received UPN to internal WCHAR representation.
+
+ m_service_name= utf8_to_wchar(target, &len);
+
+ if (m_service_name)
+ DBUG_PRINT("info", ("Using target service: %S\n", m_service_name));
+ else
+ {
+ /*
+ Note: we ignore errors here - m_target will be NULL, the target name
+ will not be used and system will fall-back to NTLM authentication. But
+ we leave trace in error log.
+ */
+ ERROR_LOG(WARNING, ("Could not decode UPN sent by the server"
+ "; target service name will not be used"
+ " and Kerberos authentication will not work"));
+ }
+}
+
+
+Handshake_client::~Handshake_client()
+{
+ if (m_service_name)
+ free(m_service_name);
+}
+
+
+Blob Handshake_client::read_packet()
+{
+ /*
+ We do a fake read in the first round because first
+ packet from the server containing UPN must be read
+ before the handshake context is created and the packet
+ processing loop starts. We return an empty blob here
+ and process_data() function will ignore it.
+ */
+ if (m_round == 1)
+ return Blob();
+
+ // Otherwise we read packet from the connection.
+
+ Blob packet= m_con.read();
+ m_error= m_con.error();
+ if (!m_error && packet.is_null())
+ m_error= true; // (no specific error code assigned)
+
+ if (m_error)
+ return Blob();
+
+ DBUG_PRINT("dump", ("Got the following bytes"));
+ DBUG_DUMP("dump", packet.ptr(), packet.len());
+ return packet;
+}
+
+
+
+int Handshake_client::write_packet(Blob &data)
+{
+ /*
+ Length of the first data payload send by client authentication plugin is
+ limited to 255 bytes (because it is wrapped inside client authentication
+ packet and is length-encoded with 1 byte for the length).
+
+ If the data payload is longer than 254 bytes, then it is sent in two parts:
+ first part of length 255 will be embedded in the authentication packet,
+ second part will be sent in the following packet. Byte 255 of the first
+ part contains information about the total length of the payload. It is a
+ number of blocks of size 512 bytes which is sufficient to store the
+ combined packets.
+
+ Server's logic for reading first client's payload is as follows
+ (see Handshake_server::read_packet()):
+ 1. Read data from the authentication packet, if it is shorter than 255 bytes
+ then that is all data sent by client.
+ 2. If there is 255 bytes of data in the authentication packet, read another
+ packet and append it to the data, skipping byte 255 of the first packet
+ which can be used to allocate buffer of appropriate size.
+ */
+
+ size_t len2= 0; // length of the second part of first data payload
+ byte saved_byte; // for saving byte 255 in which data length is stored
+
+ if (m_round == 1 && data.len() > 254)
+ {
+ len2= data.len() - 254;
+ DBUG_PRINT("info", ("Splitting first packet of length %lu"
+ ", %lu bytes will be sent in a second part",
+ data.len(), len2));
+ /*
+ Store in byte 255 the number of 512b blocks that are needed to
+ keep all the data.
+ */
+ unsigned block_count= (uint)(data.len()/512) + ((data.len() % 512) ? 1 : 0);
+
+#if !defined(DBUG_OFF) && defined(WINAUTH_USE_DBUG_LIB)
+
+ /*
+ For testing purposes, use wrong block count to see how server
+ handles this.
+ */
+ DBUG_EXECUTE_IF("winauth_first_packet_test",{
+ block_count= data.len() == 601 ? 0 :
+ data.len() == 602 ? 1 :
+ block_count;
+ });
+
+#endif
+
+ DBUG_ASSERT(block_count < (unsigned)0x100);
+ saved_byte= data[254];
+ data[254] = block_count;
+
+ data.trim(255);
+ }
+
+ DBUG_PRINT("dump", ("Sending the following data"));
+ DBUG_DUMP("dump", data.ptr(), data.len());
+ int ret= m_con.write(data);
+
+ if (ret)
+ return ret;
+
+ // Write second part if it is present.
+ if (len2)
+ {
+ data[254]= saved_byte;
+ Blob data2(data.ptr() + 254, len2);
+ DBUG_PRINT("info", ("Sending second part of data"));
+ DBUG_DUMP("info", data2.ptr(), data2.len());
+ ret= m_con.write(data2);
+ }
+
+ return ret;
+}
+
+
+/**
+ Process data sent by server.
+
+ @param[in] data blob with data from server
+
+ This method analyses data sent by server during authentication handshake.
+ If client should continue packet exchange, this method returns data to
+ be sent to the server next. If no more data needs to be exchanged, an
+ empty blob is returned and @c is_complete() is @c true. In case of error
+ an empty blob is returned and @c error() gives non-zero error code.
+
+ When invoked for the first time (in the first round of the handshake)
+ there is no data from the server (data blob is null) and the initial
+ packet is generated without an input.
+
+ @return Data to be sent to the server next or null blob if no more data
+ needs to be exchanged or in case of error.
+*/
+
+Blob Handshake_client::process_data(const Blob &data)
+{
+#if !defined(DBUG_OFF) && defined(WINAUTH_USE_DBUG_LIB)
+ /*
+ Code for testing the logic for sending the first client payload.
+
+ A fake data of length given by environment variable TEST_PACKET_LENGTH
+ (or default 255 bytes) is sent to the server. First 2 bytes of the
+ payload contain its total length (LSB first). The length of test data
+ is limited to 2048 bytes.
+
+ Upon receiving test data, server will check that data is correct and
+ refuse connection. If server detects data errors it will crash on
+ assertion.
+
+ This code is executed if debug flag "winauth_first_packet_test" is
+ set, e.g. using client option:
+
+ --debug-dbug="d,winauth_first_packet_test"
+
+ The same debug flag must be enabled in the server, e.g. using
+ statement:
+
+ SET GLOBAL debug= '+d,winauth_first_packet_test';
+ */
+
+ static byte test_buf[2048];
+
+ if (m_round == 1
+ && DBUG_EVALUATE_IF("winauth_first_packet_test", true, false))
+ {
+ const char *env= getenv("TEST_PACKET_LENGTH");
+ size_t len= env ? atoi(env) : 0;
+ if (!len)
+ len= 255;
+ if (len > sizeof(test_buf))
+ len= sizeof(test_buf);
+
+ // Store data length in first 2 bytes.
+ byte *ptr= test_buf;
+ *ptr++= len & 0xFF;
+ *ptr++= len >> 8;
+
+ // Fill remaining bytes with known values.
+ for (byte b= 0; ptr < test_buf + len; ++ptr, ++b)
+ *ptr= b;
+
+ return Blob(test_buf, len);
+ };
+
+#endif
+
+ Security_buffer input(data);
+ SECURITY_STATUS ret;
+
+ m_output.free();
+
+ ret= InitializeSecurityContextW(
+ &m_cred,
+ m_round == 1 ? NULL : &m_sctx, // partial context
+ m_service_name, // service name
+ ASC_REQ_ALLOCATE_MEMORY, // requested attributes
+ 0, // reserved
+ SECURITY_NETWORK_DREP, // data representation
+ m_round == 1 ? NULL : &input, // input data
+ 0, // reserved
+ &m_sctx, // context
+ &m_output, // output data
+ &m_atts, // attributes
+ &m_expire); // expire date
+
+ if (process_result(ret))
+ {
+ DBUG_PRINT("error",
+ ("InitializeSecurityContext() failed with error %X", ret));
+ return Blob();
+ }
+
+ return m_output.as_blob();
+}
+
+
+/**********************************************************************/
+
+
+/**
+ Perform authentication handshake from client side.
+
+ @param[in] vio pointer to @c MYSQL_PLUGIN_VIO instance to be used
+ for communication with the server
+ @param[in] mysql pointer to a MySQL connection for which we authenticate
+
+ After reading the initial packet from server, containing its UPN to be
+ used as service name, client starts packet exchange by sending the first
+ packet in this exchange. While handshake is not yet completed, client
+ reads packets sent by the server and process them, possibly generating new
+ data to be sent to the server.
+
+ This function reports errors.
+
+ @return 0 on success.
+*/
+
+int win_auth_handshake_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
+{
+ DBUG_ENTER("win_auth_handshake_client");
+
+ /*
+ Check if we should enable logging.
+ */
+ {
+ const char *opt= getenv("AUTHENTICATION_WIN_LOG");
+ int opt_val= opt ? atoi(opt) : 0;
+ if (opt && !opt_val)
+ {
+ if (!strncasecmp("on", opt, 2)) opt_val= 2;
+ if (!strncasecmp("yes", opt, 3)) opt_val= 2;
+ if (!strncasecmp("true", opt, 4)) opt_val= 2;
+ if (!strncasecmp("debug", opt, 5)) opt_val= 4;
+ if (!strncasecmp("dbug", opt, 4)) opt_val= 4;
+ }
+ set_log_level(opt_val);
+ }
+
+ ERROR_LOG(INFO, ("Authentication handshake for account %s", mysql->user));
+
+ // Create connection object.
+
+ Connection con(vio);
+ DBUG_ASSERT(!con.error());
+
+ // Read initial packet from server containing service name.
+
+ Blob service_name= con.read();
+
+ if (con.error() || service_name.is_null())
+ {
+ ERROR_LOG(ERROR, ("Error reading initial packet"));
+ DBUG_RETURN(CR_ERROR);
+ }
+ DBUG_PRINT("info", ("Got initial packet of length %d", service_name.len()));
+
+ // Create authentication handshake context using the given service name.
+
+ Handshake_client hndshk(con,
+ service_name[0] ? (char *)service_name.ptr() : NULL,
+ service_name.len());
+ if (hndshk.error())
+ {
+ ERROR_LOG(ERROR, ("Could not create authentication handshake context"));
+ DBUG_RETURN(CR_ERROR);
+ }
+
+ DBUG_ASSERT(!hndshk.error());
+
+ /*
+ Read and process packets from server until handshake is complete.
+ Note that the first read from server is dummy
+ (see Handshake_client::read_packet()) as we already have read the
+ first packet to establish service name.
+ */
+ if (hndshk.packet_processing_loop())
+ DBUG_RETURN(CR_ERROR);
+
+ DBUG_ASSERT(!hndshk.error() && hndshk.is_complete());
+
+ DBUG_RETURN(CR_OK);
+}
diff --git a/plugin/win_auth_client/log_client.cc b/plugin/win_auth_client/log_client.cc
new file mode 100644
index 00000000..2e878510
--- /dev/null
+++ b/plugin/win_auth_client/log_client.cc
@@ -0,0 +1,65 @@
+/* Copyright (c) 2011, 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
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include <my_global.h>
+#include "common.h"
+
+
+// Client-side logging function
+
+void error_log_vprint(error_log_level::type level,
+ const char *fmt, va_list args)
+{
+ const char *level_string= "";
+ int log_level= get_log_level();
+
+ switch (level)
+ {
+ case error_log_level::INFO:
+ if (3 > log_level)
+ return;
+ level_string= "Note";
+ break;
+ case error_log_level::WARNING:
+ if (2 > log_level)
+ return;
+ level_string= "Warning";
+ break;
+ case error_log_level::ERROR:
+ if (1 > log_level)
+ return;
+ level_string= "ERROR";
+ break;
+ }
+
+ fprintf(stderr, "Windows Authentication Plugin %s: ", level_string);
+ vfprintf(stderr, fmt, args);
+ fputc('\n', stderr);
+ fflush(stderr);
+}
+
+
+// Trivial implementation of log-level setting storage.
+
+void set_log_level(unsigned int level)
+{
+ opt_auth_win_log_level= level;
+}
+
+
+unsigned int get_log_level(void)
+{
+ return opt_auth_win_log_level;
+}
diff --git a/plugin/win_auth_client/plugin_client.cc b/plugin/win_auth_client/plugin_client.cc
new file mode 100644
index 00000000..37bd1bc5
--- /dev/null
+++ b/plugin/win_auth_client/plugin_client.cc
@@ -0,0 +1,68 @@
+/* Copyright (c) 2011, 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
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include <my_global.h>
+#include <mysql.h>
+#include <mysql/plugin_auth.h>
+#include <mysql/client_plugin.h>
+
+#include "common.h"
+
+/*
+ The following MS C++ specific pragma embeds a comment in the resulting
+ object file. A "lib" comment tells the linker to use the specified
+ library, thus the dependency is handled automagically.
+*/
+
+#ifdef _MSC_VER
+#pragma comment(lib, "Secur32")
+#endif
+
+static int win_auth_client_plugin_init(char*, size_t, int, va_list)
+{
+ return 0;
+}
+
+
+static int win_auth_client_plugin_deinit()
+{
+ return 0;
+}
+
+
+int win_auth_handshake_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
+
+
+/*
+ Client plugin declaration. This is added to mysql_client_builtins[]
+ in sql-common/client.c
+*/
+
+extern "C"
+st_mysql_client_plugin_AUTHENTICATION win_auth_client_plugin=
+{
+ MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
+ MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
+ "authentication_windows_client",
+ "Rafal Somla",
+ "Windows Authentication Plugin - client side",
+ {0,1,0},
+ "GPL",
+ NULL,
+ win_auth_client_plugin_init,
+ win_auth_client_plugin_deinit,
+ NULL, // option handling
+ win_auth_handshake_client
+};
diff --git a/plugin/wsrep_info/CMakeLists.txt b/plugin/wsrep_info/CMakeLists.txt
new file mode 100644
index 00000000..34aee9fb
--- /dev/null
+++ b/plugin/wsrep_info/CMakeLists.txt
@@ -0,0 +1,5 @@
+IF (WITH_WSREP)
+ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/sql
+ ${CMAKE_SOURCE_DIR}/wsrep)
+ MYSQL_ADD_PLUGIN(WSREP_INFO plugin.cc MODULE_ONLY RECOMPILE_FOR_EMBEDDED)
+ENDIF()
diff --git a/plugin/wsrep_info/mysql-test/wsrep_info/my.cnf b/plugin/wsrep_info/mysql-test/wsrep_info/my.cnf
new file mode 100644
index 00000000..8f62cfd0
--- /dev/null
+++ b/plugin/wsrep_info/mysql-test/wsrep_info/my.cnf
@@ -0,0 +1,35 @@
+# Use default setting for mysqld processes
+!include include/default_mysqld.cnf
+
+[mysqld]
+binlog-format=row
+innodb-autoinc-lock-mode=2
+wsrep_provider=@ENV.WSREP_PROVIDER
+
+[mysqld.1]
+#galera_port=@OPT.port
+#ist_port=@OPT.port
+#sst_port=@OPT.port
+wsrep-on=1
+wsrep-cluster-address=gcomm://
+wsrep_provider_options='base_port=@mysqld.1.#galera_port'
+wsrep_sst_receive_address='127.0.0.1:@mysqld.1.#sst_port'
+wsrep_node_name=test-node-1
+
+[mysqld.2]
+#galera_port=@OPT.port
+#ist_port=@OPT.port
+#sst_port=@OPT.port
+wsrep-on=1
+wsrep_cluster_address='gcomm://127.0.0.1:@mysqld.1.#galera_port'
+wsrep_provider_options='base_port=@mysqld.2.#galera_port'
+wsrep_sst_receive_address='127.0.0.1:@mysqld.2.#sst_port'
+wsrep_node_name=test-node-2
+
+[ENV]
+NODE_MYPORT_1= @mysqld.1.port
+NODE_MYSOCK_1= @mysqld.1.socket
+
+NODE_MYPORT_2= @mysqld.2.port
+NODE_MYSOCK_2= @mysqld.2.socket
+
diff --git a/plugin/wsrep_info/mysql-test/wsrep_info/r/plugin.result b/plugin/wsrep_info/mysql-test/wsrep_info/r/plugin.result
new file mode 100644
index 00000000..f99f27f3
--- /dev/null
+++ b/plugin/wsrep_info/mysql-test/wsrep_info/r/plugin.result
@@ -0,0 +1,23 @@
+connection node_2;
+connection node_1;
+# On node 1
+connection node_1;
+SELECT * FROM INFORMATION_SCHEMA.WSREP_STATUS;
+NODE_INDEX NODE_STATUS CLUSTER_STATUS CLUSTER_SIZE CLUSTER_STATE_UUID CLUSTER_STATE_SEQNO CLUSTER_CONF_ID PROTOCOL_VERSION
+<IDX> synced primary 2 <CLUSTER_STATE_UUID> 2 <CLUSTER_CONF_ID> 4
+SELECT * FROM INFORMATION_SCHEMA.WSREP_MEMBERSHIP ORDER BY NAME;
+INDEX UUID NAME ADDRESS
+<IDX> <MEMBER_ID> test-node-1 <ADDRESS>
+<IDX> <MEMBER_ID> test-node-2 <ADDRESS>
+# On node 2
+connection node_2;
+SELECT * FROM INFORMATION_SCHEMA.WSREP_STATUS;
+NODE_INDEX NODE_STATUS CLUSTER_STATUS CLUSTER_SIZE CLUSTER_STATE_UUID CLUSTER_STATE_SEQNO CLUSTER_CONF_ID PROTOCOL_VERSION
+<IDX> synced primary 2 <CLUSTER_STATE_UUID> 2 <CLUSTER_CONF_ID> 4
+SELECT * FROM INFORMATION_SCHEMA.WSREP_MEMBERSHIP ORDER BY NAME;
+INDEX UUID NAME ADDRESS
+<IDX> <MEMBER_ID> test-node-1 <ADDRESS>
+<IDX> <MEMBER_ID> test-node-2 <ADDRESS>
+disconnect node_2;
+disconnect node_1;
+# End of test
diff --git a/plugin/wsrep_info/mysql-test/wsrep_info/suite.opt b/plugin/wsrep_info/mysql-test/wsrep_info/suite.opt
new file mode 100644
index 00000000..b17344f8
--- /dev/null
+++ b/plugin/wsrep_info/mysql-test/wsrep_info/suite.opt
@@ -0,0 +1 @@
+--plugin-load-add=$WSREP_INFO_SO
diff --git a/plugin/wsrep_info/mysql-test/wsrep_info/suite.pm b/plugin/wsrep_info/mysql-test/wsrep_info/suite.pm
new file mode 100644
index 00000000..c7d4b0ad
--- /dev/null
+++ b/plugin/wsrep_info/mysql-test/wsrep_info/suite.pm
@@ -0,0 +1,27 @@
+package My::Suite::WSREP_INFO;
+use File::Basename;
+use My::Find;
+
+@ISA = qw(My::Suite);
+
+use lib 'suite';
+use wsrep::common;
+return wsrep_not_ok() if wsrep_not_ok();
+
+push @::global_suppressions,
+ (
+ qr(WSREP:.*down context.*),
+ qr(WSREP: Failed to send state UUID:.*),
+ qr(WSREP: wsrep_sst_receive_address.*),
+ qr(WSREP: Could not open saved state file for reading: .*),
+ qr(WSREP: Could not open state file for reading: .*),
+ qr(WSREP: last inactive check more than .* skipping check),
+ qr(WSREP: Gap in state sequence. Need state transfer.),
+ qr(WSREP: Failed to prepare for incremental state transfer: .*),
+ qr(WSREP: SYNC message from member .* in non-primary configuration. Ignored.),
+ qr|WSREP: access file\(.*gvwstate.dat\) failed\(No such file or directory\)|,
+ );
+
+sub is_default { 1 }
+
+bless { };
diff --git a/plugin/wsrep_info/mysql-test/wsrep_info/t/plugin.test b/plugin/wsrep_info/mysql-test/wsrep_info/t/plugin.test
new file mode 100644
index 00000000..9ae783a9
--- /dev/null
+++ b/plugin/wsrep_info/mysql-test/wsrep_info/t/plugin.test
@@ -0,0 +1,23 @@
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+--echo # On node 1
+--connection node_1
+
+--replace_column 1 <IDX> 5 <CLUSTER_STATE_UUID> 7 <CLUSTER_CONF_ID>
+SELECT * FROM INFORMATION_SCHEMA.WSREP_STATUS;
+
+--replace_column 1 <IDX> 2 <MEMBER_ID> 4 <ADDRESS>
+SELECT * FROM INFORMATION_SCHEMA.WSREP_MEMBERSHIP ORDER BY NAME;
+
+--echo # On node 2
+--connection node_2
+
+--replace_column 1 <IDX> 5 <CLUSTER_STATE_UUID> 7 <CLUSTER_CONF_ID>
+SELECT * FROM INFORMATION_SCHEMA.WSREP_STATUS;
+
+--replace_column 1 <IDX> 2 <MEMBER_ID> 4 <ADDRESS>
+SELECT * FROM INFORMATION_SCHEMA.WSREP_MEMBERSHIP ORDER BY NAME;
+
+--source include/galera_end.inc
+--echo # End of test
diff --git a/plugin/wsrep_info/plugin.cc b/plugin/wsrep_info/plugin.cc
new file mode 100644
index 00000000..51eadc9d
--- /dev/null
+++ b/plugin/wsrep_info/plugin.cc
@@ -0,0 +1,234 @@
+/* Copyright (C) 2014 MariaDB Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#ifndef MYSQL_SERVER
+#define MYSQL_SERVER
+#endif
+
+#include <my_global.h>
+#include <mysql/plugin.h>
+#include <sql_i_s.h> /* ST_SCHEMA_TABLE */
+#include <sql_show.h>
+#include <sql_acl.h> /* check_global_access() */
+#include <wsrep_mysqld.h>
+#include <wsrep_utils.h>
+
+/* WSREP_MEMBERSHIP table fields */
+
+/* Node index */
+#define COLUMN_WSREP_MEMB_INDEX 0
+/* Unique member ID */
+#define COLUMN_WSREP_MEMB_UUID 1
+/* Human-readable name */
+#define COLUMN_WSREP_MEMB_NAME 2
+/* Incoming address */
+#define COLUMN_WSREP_MEMB_ADDRESS 3
+
+/* WSREP_STATUS table fields */
+
+/* Node index */
+#define COLUMN_WSREP_STATUS_NODE_INDEX 0
+/* Node status */
+#define COLUMN_WSREP_STATUS_NODE_STATUS 1
+/* Cluster status */
+#define COLUMN_WSREP_STATUS_CLUSTER_STATUS 2
+/* Cluster size */
+#define COLUMN_WSREP_STATUS_CLUSTER_SIZE 3
+/* Global cluster state UUID */
+#define COLUMN_WSREP_STATUS_CLUSTER_STATE_UUID 4
+/* Global cluster state Sequence number */
+#define COLUMN_WSREP_STATUS_CLUSTER_STATE_SEQNO 5
+/* Cluster membership changes */
+#define COLUMN_WSREP_STATUS_CLUSTER_CONF_ID 6
+/* Application protocol version */
+#define COLUMN_WSREP_STATUS_PROTO_VERSION 7
+
+namespace Show {
+
+static ST_FIELD_INFO wsrep_memb_fields[]=
+{
+ Column("INDEX", SLong(), NOT_NULL, "Index"),
+ Column("UUID", Varchar(WSREP_UUID_STR_LEN), NOT_NULL, "Uuid"),
+ Column("NAME", Varchar(WSREP_MEMBER_NAME_LEN), NOT_NULL, "Name"),
+ Column("ADDRESS", Varchar(WSREP_INCOMING_LEN), NOT_NULL, "Address"),
+ CEnd()
+};
+
+static ST_FIELD_INFO wsrep_status_fields[]=
+{
+ Column("NODE_INDEX", SLong(), NOT_NULL, "Node_Index"),
+ Column("NODE_STATUS", Varchar(16), NOT_NULL, "Node_Status"),
+ Column("CLUSTER_STATUS", Varchar(16), NOT_NULL, "Cluster_Status"),
+ Column("CLUSTER_SIZE", SLong(), NOT_NULL, "Cluster_Size"),
+ Column("CLUSTER_STATE_UUID", Varchar(WSREP_UUID_STR_LEN), NOT_NULL),
+ Column("CLUSTER_STATE_SEQNO", SLonglong(), NOT_NULL),
+ Column("CLUSTER_CONF_ID", SLonglong(), NOT_NULL),
+ Column("PROTOCOL_VERSION", SLong(), NOT_NULL),
+ CEnd()
+};
+
+} // namespace Show
+
+static int wsrep_memb_fill_table(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+ int rc= 0;
+
+ if (check_global_access(thd, SUPER_ACL, true))
+ return rc;
+
+ wsrep_config_state->lock();
+
+ const wsrep::view& view(wsrep_config_state->get_view_info());
+ const std::vector<wsrep::view::member>& members(view.members());
+
+
+ TABLE *table= tables->table;
+
+ for (unsigned int i= 0; i < members.size(); i++)
+ {
+ table->field[COLUMN_WSREP_MEMB_INDEX]->store(i, 0);
+
+ std::ostringstream os;
+ os << members[i].id();
+ table->field[COLUMN_WSREP_MEMB_UUID]->store(os.str().c_str(),
+ os.str().length(),
+ system_charset_info);
+ table->field[COLUMN_WSREP_MEMB_NAME]->store(members[i].name().c_str(),
+ members[i].name().length(),
+ system_charset_info);
+ table->field[COLUMN_WSREP_MEMB_ADDRESS]->store(members[i].incoming().c_str(),
+ members[i].incoming().length(),
+ system_charset_info);
+
+ if (schema_table_store_record(thd, table))
+ {
+ rc= 1;
+ goto end;
+ }
+ }
+
+end:
+ wsrep_config_state->unlock();
+ return rc;
+}
+
+static int wsrep_memb_plugin_init(void *p)
+{
+ ST_SCHEMA_TABLE *schema= (ST_SCHEMA_TABLE *)p;
+
+ schema->fields_info= Show::wsrep_memb_fields;
+ schema->fill_table= wsrep_memb_fill_table;
+
+ return 0;
+}
+
+static struct st_mysql_information_schema wsrep_memb_plugin=
+{ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+static int wsrep_status_fill_table(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+ int rc= 0;
+
+ if (check_global_access(thd, SUPER_ACL, true))
+ return rc;
+
+ wsrep_config_state->lock();
+
+ const wsrep::view& view= wsrep_config_state->get_view_info();
+ enum wsrep::server_state::state status= wsrep_config_state->get_status();
+
+ TABLE *table= tables->table;
+
+ table->field[COLUMN_WSREP_STATUS_NODE_INDEX]
+ ->store(view.own_index(), 0);
+ table->field[COLUMN_WSREP_STATUS_NODE_STATUS]
+ ->store(to_c_string(status),
+ strlen(to_c_string(status)),
+ system_charset_info);
+ table->field[COLUMN_WSREP_STATUS_CLUSTER_STATUS]
+ ->store(to_c_string(view.status()),
+ strlen(to_c_string(view.status())),
+ system_charset_info);
+ table->field[COLUMN_WSREP_STATUS_CLUSTER_SIZE]->store(view.members().size(), 0);
+
+ std::ostringstream os;
+ os << view.state_id().id();
+ table->field[COLUMN_WSREP_STATUS_CLUSTER_STATE_UUID]
+ ->store(os.str().c_str(), os.str().length(), system_charset_info);
+
+ table->field[COLUMN_WSREP_STATUS_CLUSTER_STATE_SEQNO]
+ ->store(view.state_id().seqno().get(), 0);
+ table->field[COLUMN_WSREP_STATUS_CLUSTER_CONF_ID]
+ ->store(view.view_seqno().get(), 0);
+ table->field[COLUMN_WSREP_STATUS_PROTO_VERSION]
+ ->store(view.protocol_version(), 0);
+
+ if (schema_table_store_record(thd, table))
+ rc= 1;
+
+ wsrep_config_state->unlock();
+ return rc;
+}
+
+static int wsrep_status_plugin_init(void *p)
+{
+ ST_SCHEMA_TABLE *schema= (ST_SCHEMA_TABLE *)p;
+
+ schema->fields_info= Show::wsrep_status_fields;
+ schema->fill_table= wsrep_status_fill_table;
+
+ return 0;
+}
+
+static struct st_mysql_information_schema wsrep_status_plugin=
+{ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+/*
+ Plugin library descriptor
+*/
+
+maria_declare_plugin(wsrep_info)
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &wsrep_memb_plugin,
+ "WSREP_MEMBERSHIP", /* Plugin name */
+ "Nirbhay Choubey", /* Plugin author */
+ "Information about group members", /* Plugin description */
+ PLUGIN_LICENSE_GPL, /* License */
+ wsrep_memb_plugin_init, /* Plugin Init */
+ 0, /* Plugin Deinit */
+ 0x0100, /* Version (hex) */
+ NULL, /* Status variables */
+ NULL, /* System variables */
+ "1.0", /* Version (string) */
+ MariaDB_PLUGIN_MATURITY_STABLE /* Maturity */
+},
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &wsrep_status_plugin,
+ "WSREP_STATUS", /* Plugin name */
+ "Nirbhay Choubey", /* Plugin author */
+ "Group view information", /* Plugin description */
+ PLUGIN_LICENSE_GPL, /* License */
+ wsrep_status_plugin_init, /* Plugin Init */
+ 0, /* Plugin Deinit */
+ 0x0100, /* Version (hex) */
+ NULL, /* Status variables */
+ NULL, /* System variables */
+ "1.0", /* Version (string) */
+ MariaDB_PLUGIN_MATURITY_STABLE /* Maturity */
+}
+maria_declare_plugin_end;
+