1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
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
|