vincentchu-handlersocket 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. data/ext/HandlerSocket-Plugin-for-MySQL/AUTHORS +22 -0
  2. data/ext/HandlerSocket-Plugin-for-MySQL/COPYING +30 -0
  3. data/ext/HandlerSocket-Plugin-for-MySQL/ChangeLog +12 -0
  4. data/ext/HandlerSocket-Plugin-for-MySQL/Makefile.am +87 -0
  5. data/ext/HandlerSocket-Plugin-for-MySQL/README +78 -0
  6. data/ext/HandlerSocket-Plugin-for-MySQL/autogen.sh +117 -0
  7. data/ext/HandlerSocket-Plugin-for-MySQL/client/Makefile.am +24 -0
  8. data/ext/HandlerSocket-Plugin-for-MySQL/client/hsclient.cpp +88 -0
  9. data/ext/HandlerSocket-Plugin-for-MySQL/client/hslongrun.cpp +1041 -0
  10. data/ext/HandlerSocket-Plugin-for-MySQL/client/hspool_test.pl +224 -0
  11. data/ext/HandlerSocket-Plugin-for-MySQL/client/hstest.cpp +1532 -0
  12. data/ext/HandlerSocket-Plugin-for-MySQL/client/hstest.pl +228 -0
  13. data/ext/HandlerSocket-Plugin-for-MySQL/client/hstest_hs.sh +4 -0
  14. data/ext/HandlerSocket-Plugin-for-MySQL/client/hstest_hs_more50.sh +4 -0
  15. data/ext/HandlerSocket-Plugin-for-MySQL/client/hstest_md.sh +7 -0
  16. data/ext/HandlerSocket-Plugin-for-MySQL/client/hstest_my.sh +3 -0
  17. data/ext/HandlerSocket-Plugin-for-MySQL/client/hstest_my_more50.sh +3 -0
  18. data/ext/HandlerSocket-Plugin-for-MySQL/configure.ac +144 -0
  19. data/ext/HandlerSocket-Plugin-for-MySQL/docs-en/about-handlersocket.en.txt +72 -0
  20. data/ext/HandlerSocket-Plugin-for-MySQL/docs-en/configuration-options.en.txt +99 -0
  21. data/ext/HandlerSocket-Plugin-for-MySQL/docs-en/installation.en.txt +92 -0
  22. data/ext/HandlerSocket-Plugin-for-MySQL/docs-en/perl-client.en.txt +135 -0
  23. data/ext/HandlerSocket-Plugin-for-MySQL/docs-en/protocol.en.txt +205 -0
  24. data/ext/HandlerSocket-Plugin-for-MySQL/docs-ja/about-handlersocket.ja.txt +51 -0
  25. data/ext/HandlerSocket-Plugin-for-MySQL/docs-ja/installation.ja.txt +88 -0
  26. data/ext/HandlerSocket-Plugin-for-MySQL/docs-ja/perl-client.ja.txt +127 -0
  27. data/ext/HandlerSocket-Plugin-for-MySQL/docs-ja/protocol.ja.txt +180 -0
  28. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/COPYRIGHT.txt +27 -0
  29. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/Makefile.am +10 -0
  30. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/Makefile.plain.template +31 -0
  31. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/database.cpp +1190 -0
  32. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/database.hpp +142 -0
  33. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/handlersocket.cpp +222 -0
  34. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/handlersocket.spec.template +29 -0
  35. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/hstcpsvr.cpp +149 -0
  36. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/hstcpsvr.hpp +58 -0
  37. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/hstcpsvr_worker.cpp +951 -0
  38. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/hstcpsvr_worker.hpp +35 -0
  39. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/mysql_incl.hpp +50 -0
  40. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/COPYRIGHT.txt +27 -0
  41. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/Makefile.am +12 -0
  42. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/Makefile.plain +27 -0
  43. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/allocator.hpp +64 -0
  44. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/auto_addrinfo.hpp +49 -0
  45. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/auto_file.hpp +64 -0
  46. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/auto_ptrcontainer.hpp +67 -0
  47. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/config.cpp +67 -0
  48. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/config.hpp +32 -0
  49. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/escape.cpp +127 -0
  50. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/escape.hpp +66 -0
  51. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/fatal.cpp +36 -0
  52. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/fatal.hpp +22 -0
  53. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/hstcpcli.cpp +441 -0
  54. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/hstcpcli.hpp +62 -0
  55. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/libhsclient.spec.template +39 -0
  56. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/mutex.hpp +51 -0
  57. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/socket.cpp +186 -0
  58. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/socket.hpp +51 -0
  59. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/string_buffer.hpp +118 -0
  60. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/string_ref.hpp +63 -0
  61. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/string_util.cpp +182 -0
  62. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/string_util.hpp +53 -0
  63. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/thread.hpp +84 -0
  64. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/util.hpp +25 -0
  65. data/ext/HandlerSocket-Plugin-for-MySQL/misc/microbench-hs.log +130 -0
  66. data/ext/HandlerSocket-Plugin-for-MySQL/misc/microbench-my.log +125 -0
  67. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/COPYRIGHT.txt +27 -0
  68. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/Changes +6 -0
  69. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/HandlerSocket.xs +632 -0
  70. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/MANIFEST +8 -0
  71. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/Makefile.PL +18 -0
  72. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/Makefile.PL.installed +20 -0
  73. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/README +30 -0
  74. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/lib/Net/HandlerSocket.pm +68 -0
  75. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/lib/Net/HandlerSocket/Pool.pm +362 -0
  76. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/perl-Net-HandlerSocket.spec.template +127 -0
  77. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/ppport.h +6375 -0
  78. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/t/Net-HandlerSocket.t +15 -0
  79. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/Makefile +79 -0
  80. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/common/binary_my.cnf +4 -0
  81. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/common/compat.sh +29 -0
  82. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/common/hstest.pm +66 -0
  83. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/Makefile +4 -0
  84. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/run.sh +27 -0
  85. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test01.expected +100 -0
  86. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test01.pl +38 -0
  87. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test02.expected +100 -0
  88. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test02.pl +49 -0
  89. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test03.expected +771 -0
  90. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test03.pl +61 -0
  91. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test04.expected +0 -0
  92. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test04.pl +63 -0
  93. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test05.expected +771 -0
  94. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test05.pl +59 -0
  95. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test06.expected +644 -0
  96. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test06.pl +90 -0
  97. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test07.expected +304 -0
  98. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test07.pl +98 -0
  99. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test08.expected +2 -0
  100. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test08.pl +48 -0
  101. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test09.expected +12 -0
  102. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test09.pl +67 -0
  103. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test10.expected +771 -0
  104. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test10.pl +93 -0
  105. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test11.expected +37 -0
  106. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test11.pl +112 -0
  107. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test12.expected +273 -0
  108. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test12.pl +134 -0
  109. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test13.expected +92 -0
  110. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test13.pl +92 -0
  111. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test14.expected +144 -0
  112. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test14.pl +80 -0
  113. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test15.expected +764 -0
  114. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test15.pl +114 -0
  115. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test16.expected +66 -0
  116. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test16.pl +88 -0
  117. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test17.expected +0 -0
  118. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test17.pl +125 -0
  119. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test18.expected +22 -0
  120. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test18.pl +63 -0
  121. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test19.expected +14894 -0
  122. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test19.pl +190 -0
  123. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test20.expected +2 -0
  124. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test20.pl +33 -0
  125. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test21.expected +11 -0
  126. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test21.pl +58 -0
  127. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test22.expected +9 -0
  128. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test22.pl +61 -0
  129. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test23.expected +101 -0
  130. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test23.pl +53 -0
  131. data/ext/winebarrel-ruby-handlersocket-c19841e47ea2/README +33 -0
  132. data/ext/winebarrel-ruby-handlersocket-c19841e47ea2/extconf.rb +27 -0
  133. data/ext/winebarrel-ruby-handlersocket-c19841e47ea2/handlersocket.cpp +437 -0
  134. data/ext/winebarrel-ruby-handlersocket-c19841e47ea2/handlersocket.h +32 -0
  135. metadata +200 -0
@@ -0,0 +1,10 @@
1
+ pkgplugindir = $(PLUGIN_DIR)
2
+ noinst_HEADERS = database.hpp hstcpsvr.hpp hstcpsvr_worker.hpp mysql_incl.hpp
3
+ pkgplugin_LTLIBRARIES = handlersocket.la
4
+ handlersocket_la_LDFLAGS = -module ../libhsclient/libhsclient.la
5
+ handlersocket_la_CFLAGS = $(MYSQL_INC) $(MYSQL_CFLAGS) $(AM_CFLAGS) \
6
+ -I../libhsclient
7
+ handlersocket_la_CXXFLAGS = $(MYSQL_INC) $(MYSQL_CFLAGS) $(AM_CFLAGS) \
8
+ -I../libhsclient
9
+ handlersocket_la_SOURCES = database.cpp handlersocket.cpp \
10
+ hstcpsvr_worker.cpp hstcpsvr.cpp
@@ -0,0 +1,31 @@
1
+
2
+ MYSQL_INC = HANDLERSOCKET_MYSQL_INC
3
+ MYSQL_LIB = HANDLERSOCKET_MYSQL_LIB
4
+
5
+ CXX = g++ -Wall -g -fno-rtti -fno-exceptions -fPIC -DPIC
6
+ LIBS = $(MYSQL_LIB) -lhsclient -lpthread -lz
7
+ CXXFLAGS = -I/usr/include/handlersocket $(MYSQL_INC)
8
+ LDFLAGS =
9
+
10
+ CXXFLAGS += -O3 -DNDEBUG
11
+
12
+ HANDLERSOCKET_OBJS = database.o hstcpsvr.o hstcpsvr_worker.o
13
+
14
+ all: handlersocket.so
15
+
16
+ handlersocket.so: $(HANDLERSOCKET_OBJS) handlersocket.cpp
17
+ $(CXX) $(CXXFLAGS) -fno-strict-aliasing -shared $^ -o $@ $(LDFLAGS) \
18
+ -Wl,-soname -Wl,$@ $(LIBS)
19
+ clean:
20
+ rm -f *.a *.so *.o
21
+
22
+ LIBDIR = $(shell \
23
+ if [ -e /usr/lib64/mysql ]; then echo /usr/lib64; else echo /usr/lib; fi)
24
+
25
+ install: handlersocket.so
26
+ sudo sh -c 'ulimit -c unlimited ; /etc/init.d/mysql stop ; \
27
+ cp handlersocket.so handlersocket.so.cpy && \
28
+ mv handlersocket.so.cpy \
29
+ $(LIBDIR)/mysql/plugin/handlersocket.so && \
30
+ /etc/init.d/mysql start'
31
+
@@ -0,0 +1,1190 @@
1
+
2
+ // vim:sw=2:ai
3
+
4
+ /*
5
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
6
+ * See COPYRIGHT.txt for details.
7
+ */
8
+
9
+ #include <stdlib.h>
10
+ #include <stdio.h>
11
+ #include <string.h>
12
+
13
+ #include "database.hpp"
14
+ #include "string_util.hpp"
15
+ #include "escape.hpp"
16
+ #include "mysql_incl.hpp"
17
+
18
+ #define DBG_KEY(x)
19
+ #define DBG_SHUT(x)
20
+ #define DBG_LOCK(x)
21
+ #define DBG_THR(x)
22
+ #define DBG_CMP(x)
23
+ #define DBG_FLD(x)
24
+ #define DBG_FILTER(x)
25
+ #define DBG_REFCNT(x)
26
+ #define DBG_KEYLEN(x)
27
+ #define DBG_DELETED
28
+
29
+ /* status variables */
30
+ unsigned long long int open_tables_count;
31
+ unsigned long long int close_tables_count;
32
+ unsigned long long int lock_tables_count;
33
+ unsigned long long int unlock_tables_count;
34
+ unsigned long long int index_exec_count;
35
+
36
+ namespace dena {
37
+
38
+ prep_stmt::prep_stmt()
39
+ : dbctx(0), table_id(static_cast<size_t>(-1)),
40
+ idxnum(static_cast<size_t>(-1))
41
+ {
42
+ }
43
+ prep_stmt::prep_stmt(dbcontext_i *c, size_t tbl, size_t idx,
44
+ const fields_type& rf, const fields_type& ff)
45
+ : dbctx(c), table_id(tbl), idxnum(idx), ret_fields(rf), filter_fields(ff)
46
+ {
47
+ if (dbctx) {
48
+ dbctx->table_addref(table_id);
49
+ }
50
+ }
51
+ prep_stmt::~prep_stmt()
52
+ {
53
+ if (dbctx) {
54
+ dbctx->table_release(table_id);
55
+ }
56
+ }
57
+
58
+ prep_stmt::prep_stmt(const prep_stmt& x)
59
+ : dbctx(x.dbctx), table_id(x.table_id), idxnum(x.idxnum),
60
+ ret_fields(x.ret_fields), filter_fields(x.filter_fields)
61
+ {
62
+ if (dbctx) {
63
+ dbctx->table_addref(table_id);
64
+ }
65
+ }
66
+
67
+ prep_stmt&
68
+ prep_stmt::operator =(const prep_stmt& x)
69
+ {
70
+ if (this != &x) {
71
+ if (dbctx) {
72
+ dbctx->table_release(table_id);
73
+ }
74
+ dbctx = x.dbctx;
75
+ table_id = x.table_id;
76
+ idxnum = x.idxnum;
77
+ ret_fields = x.ret_fields;
78
+ filter_fields = x.filter_fields;
79
+ if (dbctx) {
80
+ dbctx->table_addref(table_id);
81
+ }
82
+ }
83
+ return *this;
84
+ }
85
+
86
+ struct database : public database_i, private noncopyable {
87
+ database(const config& c);
88
+ virtual ~database();
89
+ virtual dbcontext_ptr create_context(bool for_write) volatile;
90
+ virtual void stop() volatile;
91
+ virtual const config& get_conf() const volatile;
92
+ public:
93
+ int child_running;
94
+ private:
95
+ config conf;
96
+ };
97
+
98
+ struct tablevec_entry {
99
+ TABLE *table;
100
+ size_t refcount;
101
+ bool modified;
102
+ tablevec_entry() : table(0), refcount(0), modified(false) { }
103
+ };
104
+
105
+ struct expr_user_lock : private noncopyable {
106
+ expr_user_lock(THD *thd, int timeout)
107
+ : lck_key("handlersocket_wr", 16, &my_charset_latin1),
108
+ lck_timeout(timeout),
109
+ lck_func_get_lock(&lck_key, &lck_timeout),
110
+ lck_func_release_lock(&lck_key)
111
+ {
112
+ lck_key.fix_fields(thd, 0);
113
+ lck_timeout.fix_fields(thd, 0);
114
+ lck_func_get_lock.fix_fields(thd, 0);
115
+ lck_func_release_lock.fix_fields(thd, 0);
116
+ }
117
+ long long get_lock() {
118
+ return lck_func_get_lock.val_int();
119
+ }
120
+ long long release_lock() {
121
+ return lck_func_release_lock.val_int();
122
+ }
123
+ private:
124
+ Item_string lck_key;
125
+ Item_int lck_timeout;
126
+ Item_func_get_lock lck_func_get_lock;
127
+ Item_func_release_lock lck_func_release_lock;
128
+ };
129
+
130
+ struct dbcontext : public dbcontext_i, private noncopyable {
131
+ dbcontext(volatile database *d, bool for_write);
132
+ virtual ~dbcontext();
133
+ virtual void init_thread(const void *stack_botton,
134
+ volatile int& shutdown_flag);
135
+ virtual void term_thread();
136
+ virtual bool check_alive();
137
+ virtual void lock_tables_if();
138
+ virtual void unlock_tables_if();
139
+ virtual bool get_commit_error();
140
+ virtual void clear_error();
141
+ virtual void close_tables_if();
142
+ virtual void table_addref(size_t tbl_id);
143
+ virtual void table_release(size_t tbl_id);
144
+ virtual void cmd_open(dbcallback_i& cb, const cmd_open_args& args);
145
+ virtual void cmd_exec(dbcallback_i& cb, const cmd_exec_args& args);
146
+ virtual void set_statistics(size_t num_conns, size_t num_active);
147
+ private:
148
+ int set_thread_message(const char *fmt, ...)
149
+ __attribute__((format (printf, 2, 3)));
150
+ bool parse_fields(TABLE *const table, const char *str,
151
+ prep_stmt::fields_type& flds);
152
+ void cmd_insert_internal(dbcallback_i& cb, const prep_stmt& pst,
153
+ const string_ref *fvals, size_t fvalslen);
154
+ void cmd_sql_internal(dbcallback_i& cb, const prep_stmt& pst,
155
+ const string_ref *fvals, size_t fvalslen);
156
+ void cmd_find_internal(dbcallback_i& cb, const prep_stmt& pst,
157
+ ha_rkey_function find_flag, const cmd_exec_args& args);
158
+ size_t calc_filter_buf_size(TABLE *table, const prep_stmt& pst,
159
+ const record_filter *filters);
160
+ bool fill_filter_buf(TABLE *table, const prep_stmt& pst,
161
+ const record_filter *filters, uchar *filter_buf, size_t len);
162
+ int check_filter(dbcallback_i& cb, TABLE *table, const prep_stmt& pst,
163
+ const record_filter *filters, const uchar *filter_buf);
164
+ void resp_record(dbcallback_i& cb, TABLE *const table, const prep_stmt& pst);
165
+ void dump_record(dbcallback_i& cb, TABLE *const table, const prep_stmt& pst);
166
+ int modify_record(dbcallback_i& cb, TABLE *const table,
167
+ const prep_stmt& pst, const cmd_exec_args& args, char mod_op,
168
+ size_t& modified_count);
169
+ private:
170
+ typedef std::vector<tablevec_entry> table_vec_type;
171
+ typedef std::pair<std::string, std::string> table_name_type;
172
+ typedef std::map<table_name_type, size_t> table_map_type;
173
+ private:
174
+ volatile database *const dbref;
175
+ bool for_write_flag;
176
+ THD *thd;
177
+ MYSQL_LOCK *lock;
178
+ bool lock_failed;
179
+ std::auto_ptr<expr_user_lock> user_lock;
180
+ int user_level_lock_timeout;
181
+ bool user_level_lock_locked;
182
+ bool commit_error;
183
+ std::vector<char> info_message_buf;
184
+ table_vec_type table_vec;
185
+ table_map_type table_map;
186
+ };
187
+
188
+ database::database(const config& c)
189
+ : child_running(1), conf(c)
190
+ {
191
+ }
192
+
193
+ database::~database()
194
+ {
195
+ }
196
+
197
+ dbcontext_ptr
198
+ database::create_context(bool for_write) volatile
199
+ {
200
+ return dbcontext_ptr(new dbcontext(this, for_write));
201
+ }
202
+
203
+ void
204
+ database::stop() volatile
205
+ {
206
+ child_running = false;
207
+ }
208
+
209
+ const config&
210
+ database::get_conf() const volatile
211
+ {
212
+ return const_cast<const config&>(conf);
213
+ }
214
+
215
+ database_ptr
216
+ database_i::create(const config& conf)
217
+ {
218
+ return database_ptr(new database(conf));
219
+ }
220
+
221
+ dbcontext::dbcontext(volatile database *d, bool for_write)
222
+ : dbref(d), for_write_flag(for_write), thd(0), lock(0), lock_failed(false),
223
+ user_level_lock_timeout(0), user_level_lock_locked(false),
224
+ commit_error(false)
225
+ {
226
+ info_message_buf.resize(8192);
227
+ user_level_lock_timeout = d->get_conf().get_int("wrlock_timeout", 12);
228
+ }
229
+
230
+ dbcontext::~dbcontext()
231
+ {
232
+ }
233
+
234
+ namespace {
235
+
236
+ int
237
+ wait_server_to_start(THD *thd, volatile int& shutdown_flag)
238
+ {
239
+ int r = 0;
240
+ DBG_SHUT(fprintf(stderr, "HNDSOCK wsts\n"));
241
+ pthread_mutex_lock(&LOCK_server_started);
242
+ while (!mysqld_server_started) {
243
+ timespec abstime = { };
244
+ set_timespec(abstime, 1);
245
+ pthread_cond_timedwait(&COND_server_started, &LOCK_server_started,
246
+ &abstime);
247
+ pthread_mutex_unlock(&LOCK_server_started);
248
+ pthread_mutex_lock(&thd->mysys_var->mutex);
249
+ THD::killed_state st = thd->killed;
250
+ pthread_mutex_unlock(&thd->mysys_var->mutex);
251
+ DBG_SHUT(fprintf(stderr, "HNDSOCK wsts kst %d\n", (int)st));
252
+ pthread_mutex_lock(&LOCK_server_started);
253
+ if (st != THD::NOT_KILLED) {
254
+ DBG_SHUT(fprintf(stderr, "HNDSOCK wsts kst %d break\n", (int)st));
255
+ r = -1;
256
+ break;
257
+ }
258
+ if (shutdown_flag) {
259
+ DBG_SHUT(fprintf(stderr, "HNDSOCK wsts kst shut break\n"));
260
+ r = -1;
261
+ break;
262
+ }
263
+ }
264
+ pthread_mutex_unlock(&LOCK_server_started);
265
+ DBG_SHUT(fprintf(stderr, "HNDSOCK wsts done\n"));
266
+ return r;
267
+ }
268
+
269
+ }; // namespace
270
+
271
+ #define DENA_THR_OFFSETOF(fld) ((char *)(&thd->fld) - (char *)thd)
272
+
273
+ void
274
+ dbcontext::init_thread(const void *stack_bottom, volatile int& shutdown_flag)
275
+ {
276
+ DBG_THR(fprintf(stderr, "HNDSOCK init thread\n"));
277
+ {
278
+ my_thread_init();
279
+ thd = new THD;
280
+ thd->thread_stack = (char *)stack_bottom;
281
+ DBG_THR(fprintf(stderr,
282
+ "thread_stack = %p sizeof(THD)=%zu sizeof(mtx)=%zu "
283
+ "O: %zu %zu %zu %zu %zu %zu %zu\n",
284
+ thd->thread_stack, sizeof(THD), sizeof(LOCK_thread_count),
285
+ DENA_THR_OFFSETOF(mdl_context),
286
+ DENA_THR_OFFSETOF(net),
287
+ DENA_THR_OFFSETOF(LOCK_thd_data),
288
+ DENA_THR_OFFSETOF(mysys_var),
289
+ DENA_THR_OFFSETOF(stmt_arena),
290
+ DENA_THR_OFFSETOF(limit_found_rows),
291
+ DENA_THR_OFFSETOF(locked_tables_list)));
292
+ thd->store_globals();
293
+ thd->system_thread = static_cast<enum_thread_type>(1<<30UL);
294
+ const NET v = { 0 };
295
+ thd->net = v;
296
+ if (for_write_flag) {
297
+ #if MYSQL_VERSION_ID >= 50505
298
+ thd->variables.option_bits |= OPTION_BIN_LOG;
299
+ #else
300
+ thd->options |= OPTION_BIN_LOG;
301
+ #endif
302
+ safeFree(thd->db);
303
+ thd->db = 0;
304
+ thd->db = my_strdup("handlersocket", MYF(0));
305
+ }
306
+ my_pthread_setspecific_ptr(THR_THD, thd);
307
+ DBG_THR(fprintf(stderr, "HNDSOCK x0 %p\n", thd));
308
+ }
309
+ {
310
+ pthread_mutex_lock(&LOCK_thread_count);
311
+ thd->thread_id = thread_id++;
312
+ threads.append(thd);
313
+ ++thread_count;
314
+ pthread_mutex_unlock(&LOCK_thread_count);
315
+ }
316
+
317
+ DBG_THR(fprintf(stderr, "HNDSOCK init thread wsts\n"));
318
+ wait_server_to_start(thd, shutdown_flag);
319
+ DBG_THR(fprintf(stderr, "HNDSOCK init thread done\n"));
320
+
321
+ thd_proc_info(thd, &info_message_buf[0]);
322
+ set_thread_message("hs:listening");
323
+ DBG_THR(fprintf(stderr, "HNDSOCK x1 %p\n", thd));
324
+
325
+ lex_start(thd);
326
+
327
+ user_lock.reset(new expr_user_lock(thd, user_level_lock_timeout));
328
+ }
329
+
330
+ int
331
+ dbcontext::set_thread_message(const char *fmt, ...)
332
+ {
333
+ va_list ap;
334
+ va_start(ap, fmt);
335
+ const int n = vsnprintf(&info_message_buf[0], info_message_buf.size(),
336
+ fmt, ap);
337
+ va_end(ap);
338
+ return n;
339
+ }
340
+
341
+ void
342
+ dbcontext::term_thread()
343
+ {
344
+ DBG_THR(fprintf(stderr, "HNDSOCK thread end %p\n", thd));
345
+ unlock_tables_if();
346
+ my_pthread_setspecific_ptr(THR_THD, 0);
347
+ {
348
+ pthread_mutex_lock(&LOCK_thread_count);
349
+ delete thd;
350
+ thd = 0;
351
+ --thread_count;
352
+ pthread_mutex_unlock(&LOCK_thread_count);
353
+ my_thread_end();
354
+ }
355
+ }
356
+
357
+ bool
358
+ dbcontext::check_alive()
359
+ {
360
+ pthread_mutex_lock(&thd->mysys_var->mutex);
361
+ THD::killed_state st = thd->killed;
362
+ pthread_mutex_unlock(&thd->mysys_var->mutex);
363
+ DBG_SHUT(fprintf(stderr, "chk HNDSOCK kst %p %p %d %zu\n", thd, &thd->killed,
364
+ (int)st, sizeof(*thd)));
365
+ if (st != THD::NOT_KILLED) {
366
+ DBG_SHUT(fprintf(stderr, "chk HNDSOCK kst %d break\n", (int)st));
367
+ return false;
368
+ }
369
+ return true;
370
+ }
371
+
372
+ void
373
+ dbcontext::lock_tables_if()
374
+ {
375
+ if (lock_failed) {
376
+ return;
377
+ }
378
+ if (for_write_flag && !user_level_lock_locked) {
379
+ if (user_lock->get_lock()) {
380
+ user_level_lock_locked = true;
381
+ } else {
382
+ lock_failed = true;
383
+ return;
384
+ }
385
+ }
386
+ if (lock == 0) {
387
+ const size_t num_max = table_vec.size();
388
+ TABLE **const tables = DENA_ALLOCA_ALLOCATE(TABLE *, num_max + 1);
389
+ size_t num_open = 0;
390
+ for (size_t i = 0; i < num_max; ++i) {
391
+ if (table_vec[i].refcount > 0) {
392
+ tables[num_open++] = table_vec[i].table;
393
+ }
394
+ table_vec[i].modified = false;
395
+ }
396
+ #if MYSQL_VERSION_ID >= 50505
397
+ lock = thd->lock = mysql_lock_tables(thd, &tables[0], num_open, 0);
398
+ #else
399
+ bool need_reopen= false;
400
+ lock = thd->lock = mysql_lock_tables(thd, &tables[0], num_open,
401
+ MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN, &need_reopen);
402
+ #endif
403
+ statistic_increment(lock_tables_count, &LOCK_status);
404
+ thd_proc_info(thd, &info_message_buf[0]);
405
+ DENA_VERBOSE(100, fprintf(stderr, "HNDSOCK lock tables %p %p %zu %zu\n",
406
+ thd, lock, num_max, num_open));
407
+ if (lock == 0) {
408
+ lock_failed = true;
409
+ DENA_VERBOSE(10, fprintf(stderr, "HNDSOCK failed to lock tables %p\n",
410
+ thd));
411
+ }
412
+ if (for_write_flag) {
413
+ #if MYSQL_VERSION_ID >= 50505
414
+ thd->set_current_stmt_binlog_format_row();
415
+ #else
416
+ thd->current_stmt_binlog_row_based = 1;
417
+ #endif
418
+ }
419
+ DENA_ALLOCA_FREE(tables);
420
+ }
421
+ DBG_LOCK(fprintf(stderr, "HNDSOCK tblnum=%d\n", (int)tblnum));
422
+ }
423
+
424
+ void
425
+ dbcontext::unlock_tables_if()
426
+ {
427
+ if (lock != 0) {
428
+ DENA_VERBOSE(100, fprintf(stderr, "HNDSOCK unlock tables %p %p\n",
429
+ thd, thd->lock));
430
+ if (for_write_flag) {
431
+ for (size_t i = 0; i < table_vec.size(); ++i) {
432
+ if (table_vec[i].modified) {
433
+ query_cache_invalidate3(thd, table_vec[i].table, 1);
434
+ table_vec[i].table->file->ha_release_auto_increment();
435
+ }
436
+ }
437
+ }
438
+ {
439
+ bool suc = true;
440
+ #if MYSQL_VERSION_ID >= 50505
441
+ suc = (trans_commit_stmt(thd) == 0);
442
+ #else
443
+ suc = (ha_autocommit_or_rollback(thd, 0) == 0);
444
+ #endif
445
+ if (!suc) {
446
+ commit_error = true;
447
+ DENA_VERBOSE(10, fprintf(stderr,
448
+ "HNDSOCK unlock tables: commit failed\n"));
449
+ }
450
+ }
451
+ mysql_unlock_tables(thd, lock);
452
+ lock = thd->lock = 0;
453
+ statistic_increment(unlock_tables_count, &LOCK_status);
454
+ }
455
+ if (user_level_lock_locked) {
456
+ if (user_lock->release_lock()) {
457
+ user_level_lock_locked = false;
458
+ }
459
+ }
460
+ }
461
+
462
+ bool
463
+ dbcontext::get_commit_error()
464
+ {
465
+ return commit_error;
466
+ }
467
+
468
+ void
469
+ dbcontext::clear_error()
470
+ {
471
+ lock_failed = false;
472
+ commit_error = false;
473
+ }
474
+
475
+ void
476
+ dbcontext::close_tables_if()
477
+ {
478
+ unlock_tables_if();
479
+ DENA_VERBOSE(100, fprintf(stderr, "HNDSOCK close tables\n"));
480
+ close_thread_tables(thd);
481
+ #if MYSQL_VERSION_ID >= 50505
482
+ thd->mdl_context.release_transactional_locks();
483
+ #endif
484
+ if (!table_vec.empty()) {
485
+ statistic_increment(close_tables_count, &LOCK_status);
486
+ table_vec.clear();
487
+ table_map.clear();
488
+ }
489
+ }
490
+
491
+ void
492
+ dbcontext::table_addref(size_t tbl_id)
493
+ {
494
+ table_vec[tbl_id].refcount += 1;
495
+ DBG_REFCNT(fprintf(stderr, "%p %zu %zu addref\n", this, tbl_id,
496
+ table_vec[tbl_id].refcount));
497
+ }
498
+
499
+ void
500
+ dbcontext::table_release(size_t tbl_id)
501
+ {
502
+ table_vec[tbl_id].refcount -= 1;
503
+ DBG_REFCNT(fprintf(stderr, "%p %zu %zu release\n", this, tbl_id,
504
+ table_vec[tbl_id].refcount));
505
+ }
506
+
507
+ void
508
+ dbcontext::resp_record(dbcallback_i& cb, TABLE *const table,
509
+ const prep_stmt& pst)
510
+ {
511
+ char rwpstr_buf[64];
512
+ String rwpstr(rwpstr_buf, sizeof(rwpstr_buf), &my_charset_bin);
513
+ const prep_stmt::fields_type& rf = pst.get_ret_fields();
514
+ const size_t n = rf.size();
515
+ for (size_t i = 0; i < n; ++i) {
516
+ uint32_t fn = rf[i];
517
+ Field *const fld = table->field[fn];
518
+ DBG_FLD(fprintf(stderr, "fld=%p %zu\n", fld, fn));
519
+ if (fld->is_null()) {
520
+ /* null */
521
+ cb.dbcb_resp_entry(0, 0);
522
+ } else {
523
+ fld->val_str(&rwpstr, &rwpstr);
524
+ const size_t len = rwpstr.length();
525
+ if (len != 0) {
526
+ /* non-empty */
527
+ cb.dbcb_resp_entry(rwpstr.ptr(), rwpstr.length());
528
+ } else {
529
+ /* empty */
530
+ static const char empty_str[] = "";
531
+ cb.dbcb_resp_entry(empty_str, 0);
532
+ }
533
+ }
534
+ }
535
+ }
536
+
537
+ void
538
+ dbcontext::dump_record(dbcallback_i& cb, TABLE *const table,
539
+ const prep_stmt& pst)
540
+ {
541
+ char rwpstr_buf[64];
542
+ String rwpstr(rwpstr_buf, sizeof(rwpstr_buf), &my_charset_bin);
543
+ const prep_stmt::fields_type& rf = pst.get_ret_fields();
544
+ const size_t n = rf.size();
545
+ for (size_t i = 0; i < n; ++i) {
546
+ uint32_t fn = rf[i];
547
+ Field *const fld = table->field[fn];
548
+ if (fld->is_null()) {
549
+ /* null */
550
+ fprintf(stderr, "NULL");
551
+ } else {
552
+ fld->val_str(&rwpstr, &rwpstr);
553
+ const std::string s(rwpstr.ptr(), rwpstr.length());
554
+ fprintf(stderr, "[%s]", s.c_str());
555
+ }
556
+ }
557
+ fprintf(stderr, "\n");
558
+ }
559
+
560
+ int
561
+ dbcontext::modify_record(dbcallback_i& cb, TABLE *const table,
562
+ const prep_stmt& pst, const cmd_exec_args& args, char mod_op,
563
+ size_t& modified_count)
564
+ {
565
+ if (mod_op == 'U') {
566
+ /* update */
567
+ handler *const hnd = table->file;
568
+ uchar *const buf = table->record[0];
569
+ store_record(table, record[1]);
570
+ const prep_stmt::fields_type& rf = pst.get_ret_fields();
571
+ const size_t n = rf.size();
572
+ for (size_t i = 0; i < n; ++i) {
573
+ const string_ref& nv = args.uvals[i];
574
+ uint32_t fn = rf[i];
575
+ Field *const fld = table->field[fn];
576
+ if (nv.begin() == 0) {
577
+ fld->set_null();
578
+ } else {
579
+ fld->set_notnull();
580
+ fld->store(nv.begin(), nv.size(), &my_charset_bin);
581
+ }
582
+ }
583
+ table_vec[pst.get_table_id()].modified = true;
584
+ const int r = hnd->ha_update_row(table->record[1], buf);
585
+ if (r != 0 && r != HA_ERR_RECORD_IS_THE_SAME) {
586
+ return r;
587
+ }
588
+ ++modified_count; /* TODO: HA_ERR_RECORD_IS_THE_SAME? */
589
+ } else if (mod_op == 'D') {
590
+ /* delete */
591
+ handler *const hnd = table->file;
592
+ table_vec[pst.get_table_id()].modified = true;
593
+ const int r = hnd->ha_delete_row(table->record[0]);
594
+ if (r != 0) {
595
+ return r;
596
+ }
597
+ ++modified_count;
598
+ } else if (mod_op == '+' || mod_op == '-') {
599
+ /* increment/decrement */
600
+ handler *const hnd = table->file;
601
+ uchar *const buf = table->record[0];
602
+ store_record(table, record[1]);
603
+ const prep_stmt::fields_type& rf = pst.get_ret_fields();
604
+ const size_t n = rf.size();
605
+ size_t i = 0;
606
+ for (i = 0; i < n; ++i) {
607
+ const string_ref& nv = args.uvals[i];
608
+ uint32_t fn = rf[i];
609
+ Field *const fld = table->field[fn];
610
+ if (fld->is_null() || nv.begin() == 0) {
611
+ continue;
612
+ }
613
+ const long long pval = fld->val_int();
614
+ const long long llv = atoll_nocheck(nv.begin(), nv.end());
615
+ /* TODO: llv == 0? */
616
+ long long nval = 0;
617
+ if (mod_op == '+') {
618
+ /* increment */
619
+ nval = pval + llv;
620
+ } else {
621
+ /* decrement */
622
+ nval = pval - llv;
623
+ if ((pval < 0 && nval > 0) || (pval > 0 && nval < 0)) {
624
+ break; /* don't modify */
625
+ }
626
+ }
627
+ fld->store(nval, false);
628
+ }
629
+ if (i == n) {
630
+ /* modify */
631
+ table_vec[pst.get_table_id()].modified = true;
632
+ const int r = hnd->ha_update_row(table->record[1], buf);
633
+ if (r != 0 && r != HA_ERR_RECORD_IS_THE_SAME) {
634
+ return r;
635
+ }
636
+ ++modified_count;
637
+ }
638
+ }
639
+ return 0;
640
+ }
641
+
642
+ void
643
+ dbcontext::cmd_insert_internal(dbcallback_i& cb, const prep_stmt& pst,
644
+ const string_ref *fvals, size_t fvalslen)
645
+ {
646
+ if (!for_write_flag) {
647
+ return cb.dbcb_resp_short(2, "readonly");
648
+ }
649
+ lock_tables_if();
650
+ if (lock == 0) {
651
+ return cb.dbcb_resp_short(1, "lock_tables");
652
+ }
653
+ if (pst.get_table_id() >= table_vec.size()) {
654
+ return cb.dbcb_resp_short(2, "tblnum");
655
+ }
656
+ TABLE *const table = table_vec[pst.get_table_id()].table;
657
+ handler *const hnd = table->file;
658
+ uchar *const buf = table->record[0];
659
+ empty_record(table);
660
+ memset(buf, 0, table->s->null_bytes); /* clear null flags */
661
+ const prep_stmt::fields_type& rf = pst.get_ret_fields();
662
+ const size_t n = rf.size();
663
+ for (size_t i = 0; i < n; ++i) {
664
+ uint32_t fn = rf[i];
665
+ Field *const fld = table->field[fn];
666
+ if (fvals[i].begin() == 0) {
667
+ fld->set_null();
668
+ } else {
669
+ fld->store(fvals[i].begin(), fvals[i].size(), &my_charset_bin);
670
+ }
671
+ }
672
+ table->next_number_field = table->found_next_number_field;
673
+ /* FIXME: test */
674
+ const int r = hnd->ha_write_row(buf);
675
+ const ulonglong insert_id = table->file->insert_id_for_cur_row;
676
+ table->next_number_field = 0;
677
+ table_vec[pst.get_table_id()].modified = true;
678
+ if (r == 0 && table->found_next_number_field != 0) {
679
+ return cb.dbcb_resp_short_num64(0, insert_id);
680
+ }
681
+ if (r != 0) {
682
+ return cb.dbcb_resp_short_num(1, r);
683
+ }
684
+ return cb.dbcb_resp_short(0, "");
685
+ }
686
+
687
+ void
688
+ dbcontext::cmd_sql_internal(dbcallback_i& cb, const prep_stmt& pst,
689
+ const string_ref *fvals, size_t fvalslen)
690
+ {
691
+ if (fvalslen < 1) {
692
+ return cb.dbcb_resp_short(2, "syntax");
693
+ }
694
+ return cb.dbcb_resp_short(2, "notimpl");
695
+ }
696
+
697
+ static size_t
698
+ prepare_keybuf(const cmd_exec_args& args, uchar *key_buf, TABLE *table,
699
+ KEY& kinfo, size_t invalues_index)
700
+ {
701
+ size_t kplen_sum = 0;
702
+ DBG_KEY(fprintf(stderr, "SLOW\n"));
703
+ for (size_t i = 0; i < args.kvalslen; ++i) {
704
+ const KEY_PART_INFO & kpt = kinfo.key_part[i];
705
+ string_ref kval = args.kvals[i];
706
+ if (args.invalues_keypart >= 0 &&
707
+ static_cast<size_t>(args.invalues_keypart) == i) {
708
+ kval = args.invalues[invalues_index];
709
+ }
710
+ if (kval.begin() == 0) {
711
+ kpt.field->set_null();
712
+ } else {
713
+ kpt.field->set_notnull();
714
+ }
715
+ kpt.field->store(kval.begin(), kval.size(), &my_charset_bin);
716
+ kplen_sum += kpt.store_length;
717
+ DBG_KEYLEN(fprintf(stderr, "l=%u sl=%zu\n", kpt.length,
718
+ kpt.store_length));
719
+ }
720
+ key_copy(key_buf, table->record[0], &kinfo, kplen_sum);
721
+ DBG_KEYLEN(fprintf(stderr, "sum=%zu flen=%u\n", kplen_sum,
722
+ kinfo.key_length));
723
+ return kplen_sum;
724
+ }
725
+
726
+ void
727
+ dbcontext::cmd_find_internal(dbcallback_i& cb, const prep_stmt& pst,
728
+ ha_rkey_function find_flag, const cmd_exec_args& args)
729
+ {
730
+ const bool debug_out = (verbose_level >= 100);
731
+ bool need_resp_record = true;
732
+ char mod_op = 0;
733
+ const string_ref& mod_op_str = args.mod_op;
734
+ if (mod_op_str.size() != 0) {
735
+ if (!for_write_flag) {
736
+ return cb.dbcb_resp_short(2, "readonly");
737
+ }
738
+ mod_op = mod_op_str.begin()[0];
739
+ need_resp_record = mod_op_str.size() > 1 && mod_op_str.begin()[1] == '?';
740
+ switch (mod_op) {
741
+ case 'U': /* update */
742
+ case 'D': /* delete */
743
+ case '+': /* increment */
744
+ case '-': /* decrement */
745
+ break;
746
+ default:
747
+ if (debug_out) {
748
+ fprintf(stderr, "unknown modop: %c\n", mod_op);
749
+ }
750
+ return cb.dbcb_resp_short(2, "modop");
751
+ }
752
+ }
753
+ lock_tables_if();
754
+ if (lock == 0) {
755
+ return cb.dbcb_resp_short(1, "lock_tables");
756
+ }
757
+ if (pst.get_table_id() >= table_vec.size()) {
758
+ return cb.dbcb_resp_short(2, "tblnum");
759
+ }
760
+ TABLE *const table = table_vec[pst.get_table_id()].table;
761
+ /* keys */
762
+ if (pst.get_idxnum() >= table->s->keys) {
763
+ return cb.dbcb_resp_short(2, "idxnum");
764
+ }
765
+ KEY& kinfo = table->key_info[pst.get_idxnum()];
766
+ if (args.kvalslen > kinfo.key_parts) {
767
+ return cb.dbcb_resp_short(2, "kpnum");
768
+ }
769
+ uchar *const key_buf = DENA_ALLOCA_ALLOCATE(uchar, kinfo.key_length);
770
+ size_t invalues_idx = 0;
771
+ size_t kplen_sum = prepare_keybuf(args, key_buf, table, kinfo, invalues_idx);
772
+ /* filters */
773
+ uchar *filter_buf = 0;
774
+ if (args.filters != 0) {
775
+ const size_t filter_buf_len = calc_filter_buf_size(table, pst,
776
+ args.filters);
777
+ filter_buf = DENA_ALLOCA_ALLOCATE(uchar, filter_buf_len);
778
+ if (!fill_filter_buf(table, pst, args.filters, filter_buf,
779
+ filter_buf_len)) {
780
+ return cb.dbcb_resp_short(2, "filterblob");
781
+ }
782
+ }
783
+ /* handler */
784
+ table->read_set = &table->s->all_set;
785
+ handler *const hnd = table->file;
786
+ if (!for_write_flag) {
787
+ hnd->init_table_handle_for_HANDLER();
788
+ }
789
+ hnd->ha_index_or_rnd_end();
790
+ hnd->ha_index_init(pst.get_idxnum(), 1);
791
+ if (need_resp_record) {
792
+ cb.dbcb_resp_begin(pst.get_ret_fields().size());
793
+ }
794
+ const uint32_t limit = args.limit ? args.limit : 1;
795
+ uint32_t skip = args.skip;
796
+ size_t modified_count = 0;
797
+ int r = 0;
798
+ bool is_first = true;
799
+ bool in_loop = false;
800
+ for (uint32_t cnt = 0; cnt < limit + skip;) {
801
+ if (is_first) {
802
+ is_first = false;
803
+ const key_part_map kpm = (1U << args.kvalslen) - 1;
804
+ r = hnd->index_read_map(table->record[0], key_buf, kpm, find_flag);
805
+ if (args.invalues_keypart >= 0) {
806
+ in_loop = true;
807
+ }
808
+ } else if (!in_loop && args.invalues_keypart >= 0) {
809
+ if (++invalues_idx >= args.invalueslen) {
810
+ break;
811
+ }
812
+ kplen_sum = prepare_keybuf(args, key_buf, table, kinfo, invalues_idx);
813
+ const key_part_map kpm = (1U << args.kvalslen) - 1;
814
+ r = hnd->index_read_map(table->record[0], key_buf, kpm, find_flag);
815
+ in_loop = true;
816
+ } else {
817
+ switch (find_flag) {
818
+ case HA_READ_BEFORE_KEY:
819
+ case HA_READ_KEY_OR_PREV:
820
+ r = hnd->index_prev(table->record[0]);
821
+ break;
822
+ case HA_READ_AFTER_KEY:
823
+ case HA_READ_KEY_OR_NEXT:
824
+ r = hnd->index_next(table->record[0]);
825
+ break;
826
+ case HA_READ_KEY_EXACT:
827
+ r = hnd->index_next_same(table->record[0], key_buf, kplen_sum);
828
+ break;
829
+ default:
830
+ r = HA_ERR_END_OF_FILE; /* to finish the loop */
831
+ break;
832
+ }
833
+ }
834
+ if (debug_out) {
835
+ fprintf(stderr, "r=%d\n", r);
836
+ if (r == 0 || r == HA_ERR_RECORD_DELETED) {
837
+ dump_record(cb, table, pst);
838
+ }
839
+ }
840
+ int filter_res = 0;
841
+ if (r != 0) {
842
+ /* no-count */
843
+ } else if (args.filters != 0 && (filter_res = check_filter(cb, table,
844
+ pst, args.filters, filter_buf)) != 0) {
845
+ if (filter_res < 0) {
846
+ break;
847
+ }
848
+ } else if (skip > 0) {
849
+ --skip;
850
+ } else {
851
+ /* hit */
852
+ if (need_resp_record) {
853
+ resp_record(cb, table, pst);
854
+ }
855
+ if (mod_op != 0) {
856
+ r = modify_record(cb, table, pst, args, mod_op, modified_count);
857
+ }
858
+ ++cnt;
859
+ }
860
+ if (args.invalues_keypart >= 0 && r != 0 ) {
861
+ in_loop = false;
862
+ continue;
863
+ }
864
+ if (r != 0 && r != HA_ERR_RECORD_DELETED) {
865
+ break;
866
+ }
867
+ }
868
+ hnd->ha_index_or_rnd_end();
869
+ if (r != 0 && r != HA_ERR_RECORD_DELETED && r != HA_ERR_KEY_NOT_FOUND &&
870
+ r != HA_ERR_END_OF_FILE) {
871
+ /* failed */
872
+ if (need_resp_record) {
873
+ /* revert dbcb_resp_begin() and dbcb_resp_entry() */
874
+ cb.dbcb_resp_cancel();
875
+ }
876
+ cb.dbcb_resp_short_num(1, r);
877
+ } else {
878
+ /* succeeded */
879
+ if (need_resp_record) {
880
+ cb.dbcb_resp_end();
881
+ } else {
882
+ cb.dbcb_resp_short_num(0, modified_count);
883
+ }
884
+ }
885
+ DENA_ALLOCA_FREE(filter_buf);
886
+ DENA_ALLOCA_FREE(key_buf);
887
+ }
888
+
889
+ size_t
890
+ dbcontext::calc_filter_buf_size(TABLE *table, const prep_stmt& pst,
891
+ const record_filter *filters)
892
+ {
893
+ size_t filter_buf_len = 0;
894
+ for (const record_filter *f = filters; f->op.begin() != 0; ++f) {
895
+ if (f->val.begin() == 0) {
896
+ continue;
897
+ }
898
+ const uint32_t fn = pst.get_filter_fields()[f->ff_offset];
899
+ filter_buf_len += table->field[fn]->pack_length();
900
+ }
901
+ ++filter_buf_len;
902
+ /* Field_medium::cmp() calls uint3korr(), which may read 4 bytes.
903
+ Allocate 1 more byte for safety. */
904
+ return filter_buf_len;
905
+ }
906
+
907
+ bool
908
+ dbcontext::fill_filter_buf(TABLE *table, const prep_stmt& pst,
909
+ const record_filter *filters, uchar *filter_buf, size_t len)
910
+ {
911
+ memset(filter_buf, 0, len);
912
+ size_t pos = 0;
913
+ for (const record_filter *f = filters; f->op.begin() != 0; ++f) {
914
+ if (f->val.begin() == 0) {
915
+ continue;
916
+ }
917
+ const uint32_t fn = pst.get_filter_fields()[f->ff_offset];
918
+ Field *const fld = table->field[fn];
919
+ if ((fld->flags & BLOB_FLAG) != 0) {
920
+ return false;
921
+ }
922
+ fld->store(f->val.begin(), f->val.size(), &my_charset_bin);
923
+ const size_t packlen = fld->pack_length();
924
+ memcpy(filter_buf + pos, fld->ptr, packlen);
925
+ pos += packlen;
926
+ }
927
+ return true;
928
+ }
929
+
930
+ int
931
+ dbcontext::check_filter(dbcallback_i& cb, TABLE *table, const prep_stmt& pst,
932
+ const record_filter *filters, const uchar *filter_buf)
933
+ {
934
+ DBG_FILTER(fprintf(stderr, "check_filter\n"));
935
+ size_t pos = 0;
936
+ for (const record_filter *f = filters; f->op.begin() != 0; ++f) {
937
+ const string_ref& op = f->op;
938
+ const string_ref& val = f->val;
939
+ const uint32_t fn = pst.get_filter_fields()[f->ff_offset];
940
+ Field *const fld = table->field[fn];
941
+ const size_t packlen = fld->pack_length();
942
+ const uchar *const bval = filter_buf + pos;
943
+ int cv = 0;
944
+ if (fld->is_null()) {
945
+ cv = (val.begin() == 0) ? 0 : -1;
946
+ } else {
947
+ cv = (val.begin() == 0) ? 1 : fld->cmp(bval);
948
+ }
949
+ DBG_FILTER(fprintf(stderr, "check_filter cv=%d\n", cv));
950
+ bool cond = true;
951
+ if (op.size() == 1) {
952
+ switch (op.begin()[0]) {
953
+ case '>':
954
+ DBG_FILTER(fprintf(stderr, "check_filter op: >\n"));
955
+ cond = (cv > 0);
956
+ break;
957
+ case '<':
958
+ DBG_FILTER(fprintf(stderr, "check_filter op: <\n"));
959
+ cond = (cv < 0);
960
+ break;
961
+ case '=':
962
+ DBG_FILTER(fprintf(stderr, "check_filter op: =\n"));
963
+ cond = (cv == 0);
964
+ break;
965
+ default:
966
+ DBG_FILTER(fprintf(stderr, "check_filter op: unknown\n"));
967
+ cond = false; /* FIXME: error */
968
+ break;
969
+ }
970
+ } else if (op.size() == 2 && op.begin()[1] == '=') {
971
+ switch (op.begin()[0]) {
972
+ case '>':
973
+ DBG_FILTER(fprintf(stderr, "check_filter op: >=\n"));
974
+ cond = (cv >= 0);
975
+ break;
976
+ case '<':
977
+ DBG_FILTER(fprintf(stderr, "check_filter op: <=\n"));
978
+ cond = (cv <= 0);
979
+ break;
980
+ case '!':
981
+ DBG_FILTER(fprintf(stderr, "check_filter op: !=\n"));
982
+ cond = (cv != 0);
983
+ break;
984
+ default:
985
+ DBG_FILTER(fprintf(stderr, "check_filter op: unknown\n"));
986
+ cond = false; /* FIXME: error */
987
+ break;
988
+ }
989
+ }
990
+ DBG_FILTER(fprintf(stderr, "check_filter cond: %d\n", (int)cond));
991
+ if (!cond) {
992
+ return (f->filter_type == record_filter_type_skip) ? 1 : -1;
993
+ }
994
+ if (val.begin() != 0) {
995
+ pos += packlen;
996
+ }
997
+ }
998
+ return 0;
999
+ }
1000
+
1001
+ void
1002
+ dbcontext::cmd_open(dbcallback_i& cb, const cmd_open_args& arg)
1003
+ {
1004
+ unlock_tables_if();
1005
+ const table_name_type k = std::make_pair(std::string(arg.dbn),
1006
+ std::string(arg.tbl));
1007
+ const table_map_type::const_iterator iter = table_map.find(k);
1008
+ uint32_t tblnum = 0;
1009
+ if (iter != table_map.end()) {
1010
+ tblnum = iter->second;
1011
+ DBG_CMP(fprintf(stderr, "HNDSOCK k=%s tblnum=%d\n", k.c_str(),
1012
+ (int)tblnum));
1013
+ } else {
1014
+ TABLE_LIST tables;
1015
+ TABLE *table = 0;
1016
+ bool refresh = true;
1017
+ const thr_lock_type lock_type = for_write_flag ? TL_WRITE : TL_READ;
1018
+ #if MYSQL_VERSION_ID >= 50505
1019
+ tables.init_one_table(arg.dbn, strlen(arg.dbn), arg.tbl, strlen(arg.tbl),
1020
+ arg.tbl, lock_type);
1021
+ tables.mdl_request.init(MDL_key::TABLE, arg.dbn, arg.tbl,
1022
+ for_write_flag ? MDL_SHARED_WRITE : MDL_SHARED_READ, MDL_TRANSACTION);
1023
+ Open_table_context ot_act(thd, 0);
1024
+ if (!open_table(thd, &tables, thd->mem_root, &ot_act)) {
1025
+ table = tables.table;
1026
+ }
1027
+ #else
1028
+ tables.init_one_table(arg.dbn, arg.tbl, lock_type);
1029
+ table = open_table(thd, &tables, thd->mem_root, &refresh,
1030
+ OPEN_VIEW_NO_PARSE);
1031
+ #endif
1032
+ if (table == 0) {
1033
+ DENA_VERBOSE(20, fprintf(stderr,
1034
+ "HNDSOCK failed to open %p [%s] [%s] [%d]\n",
1035
+ thd, arg.dbn, arg.tbl, static_cast<int>(refresh)));
1036
+ return cb.dbcb_resp_short(1, "open_table");
1037
+ }
1038
+ statistic_increment(open_tables_count, &LOCK_status);
1039
+ table->reginfo.lock_type = lock_type;
1040
+ table->use_all_columns();
1041
+ tblnum = table_vec.size();
1042
+ tablevec_entry e;
1043
+ e.table = table;
1044
+ table_vec.push_back(e);
1045
+ table_map[k] = tblnum;
1046
+ }
1047
+ size_t idxnum = static_cast<size_t>(-1);
1048
+ if (arg.idx[0] >= '0' && arg.idx[0] <= '9') {
1049
+ /* numeric */
1050
+ TABLE *const table = table_vec[tblnum].table;
1051
+ idxnum = atoi(arg.idx);
1052
+ if (idxnum >= table->s->keys) {
1053
+ return cb.dbcb_resp_short(2, "idxnum");
1054
+ }
1055
+ } else {
1056
+ const char *const idx_name_to_open =
1057
+ arg.idx[0] == '\0' ? "PRIMARY" : arg.idx;
1058
+ TABLE *const table = table_vec[tblnum].table;
1059
+ for (uint i = 0; i < table->s->keys; ++i) {
1060
+ KEY& kinfo = table->key_info[i];
1061
+ if (strcmp(kinfo.name, idx_name_to_open) == 0) {
1062
+ idxnum = i;
1063
+ break;
1064
+ }
1065
+ }
1066
+ }
1067
+ if (idxnum == size_t(-1)) {
1068
+ return cb.dbcb_resp_short(2, "idxnum");
1069
+ }
1070
+ prep_stmt::fields_type rf;
1071
+ prep_stmt::fields_type ff;
1072
+ if (!parse_fields(table_vec[tblnum].table, arg.retflds, rf)) {
1073
+ return cb.dbcb_resp_short(2, "fld");
1074
+ }
1075
+ if (!parse_fields(table_vec[tblnum].table, arg.filflds, ff)) {
1076
+ return cb.dbcb_resp_short(2, "fld");
1077
+ }
1078
+ prep_stmt p(this, tblnum, idxnum, rf, ff);
1079
+ cb.dbcb_set_prep_stmt(arg.pst_id, p);
1080
+ return cb.dbcb_resp_short(0, "");
1081
+ }
1082
+
1083
+ bool
1084
+ dbcontext::parse_fields(TABLE *const table, const char *str,
1085
+ prep_stmt::fields_type& flds)
1086
+ {
1087
+ string_ref flds_sr(str, strlen(str));
1088
+ std::vector<string_ref> fldnms;
1089
+ if (flds_sr.size() != 0) {
1090
+ split(',', flds_sr, fldnms);
1091
+ }
1092
+ for (size_t i = 0; i < fldnms.size(); ++i) {
1093
+ Field **fld = 0;
1094
+ size_t j = 0;
1095
+ for (fld = table->field; *fld; ++fld, ++j) {
1096
+ DBG_FLD(fprintf(stderr, "f %s\n", (*fld)->field_name));
1097
+ string_ref fn((*fld)->field_name, strlen((*fld)->field_name));
1098
+ if (fn == fldnms[i]) {
1099
+ break;
1100
+ }
1101
+ }
1102
+ if (*fld == 0) {
1103
+ DBG_FLD(fprintf(stderr, "UNKNOWN FLD %s [%s]\n", retflds,
1104
+ std::string(fldnms[i].begin(), fldnms[i].size()).c_str()));
1105
+ return false;
1106
+ }
1107
+ DBG_FLD(fprintf(stderr, "FLD %s %zu\n", (*fld)->field_name, j));
1108
+ flds.push_back(j);
1109
+ }
1110
+ return true;
1111
+ }
1112
+
1113
+ enum db_write_op {
1114
+ db_write_op_none = 0,
1115
+ db_write_op_insert = 1,
1116
+ db_write_op_sql = 2,
1117
+ };
1118
+
1119
+ void
1120
+ dbcontext::cmd_exec(dbcallback_i& cb, const cmd_exec_args& args)
1121
+ {
1122
+ const prep_stmt& p = *args.pst;
1123
+ if (p.get_table_id() == static_cast<size_t>(-1)) {
1124
+ return cb.dbcb_resp_short(2, "stmtnum");
1125
+ }
1126
+ ha_rkey_function find_flag = HA_READ_KEY_EXACT;
1127
+ db_write_op wrop = db_write_op_none;
1128
+ if (args.op.size() == 1) {
1129
+ switch (args.op.begin()[0]) {
1130
+ case '=':
1131
+ find_flag = HA_READ_KEY_EXACT;
1132
+ break;
1133
+ case '>':
1134
+ find_flag = HA_READ_AFTER_KEY;
1135
+ break;
1136
+ case '<':
1137
+ find_flag = HA_READ_BEFORE_KEY;
1138
+ break;
1139
+ case '+':
1140
+ wrop = db_write_op_insert;
1141
+ break;
1142
+ case 'S':
1143
+ wrop = db_write_op_sql;
1144
+ break;
1145
+ default:
1146
+ return cb.dbcb_resp_short(2, "op");
1147
+ }
1148
+ } else if (args.op.size() == 2 && args.op.begin()[1] == '=') {
1149
+ switch (args.op.begin()[0]) {
1150
+ case '>':
1151
+ find_flag = HA_READ_KEY_OR_NEXT;
1152
+ break;
1153
+ case '<':
1154
+ find_flag = HA_READ_KEY_OR_PREV;
1155
+ break;
1156
+ default:
1157
+ return cb.dbcb_resp_short(2, "op");
1158
+ }
1159
+ } else {
1160
+ return cb.dbcb_resp_short(2, "op");
1161
+ }
1162
+ if (args.kvalslen <= 0) {
1163
+ return cb.dbcb_resp_short(2, "klen");
1164
+ }
1165
+ switch (wrop) {
1166
+ case db_write_op_none:
1167
+ return cmd_find_internal(cb, p, find_flag, args);
1168
+ case db_write_op_insert:
1169
+ return cmd_insert_internal(cb, p, args.kvals, args.kvalslen);
1170
+ case db_write_op_sql:
1171
+ return cmd_sql_internal(cb, p, args.kvals, args.kvalslen);
1172
+ }
1173
+ }
1174
+
1175
+ void
1176
+ dbcontext::set_statistics(size_t num_conns, size_t num_active)
1177
+ {
1178
+ thd_proc_info(thd, &info_message_buf[0]);
1179
+ if (for_write_flag) {
1180
+ set_thread_message("handlersocket: mode=wr, %zu conns, %zu active",
1181
+ num_conns, num_active);
1182
+ } else {
1183
+ set_thread_message("handlersocket: mode=rd, %zu conns, %zu active",
1184
+ num_conns, num_active);
1185
+ }
1186
+ }
1187
+
1188
+ };
1189
+
1190
+