Merge of patch lp:~ahiguti100/maria/handlersocket-fix-78 by Akira Higuchi

A bugfix of HandlerSocket is not applied to mariadb yet
This commit is contained in:
Michael Widenius 2013-05-10 16:01:38 +03:00
parent 53d44ad18b
commit 7202c21b34
15 changed files with 256 additions and 108 deletions

View File

@ -66,7 +66,7 @@ Here is a list of other language bindings:
https://github.com/koichik/node-handlersocket https://github.com/koichik/node-handlersocket
The home of HandlerSocket is here: The home of HandlerSocket is here:
https://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL https://github.com/DeNADev/HandlerSocket-Plugin-for-MySQL
More documents are available in docs-en/ and docs-ja/ directories. More documents are available in docs-en/ and docs-ja/ directories.

View File

@ -17,10 +17,11 @@ crash, etc).
$ ./autogen.sh $ ./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 $ ./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, --with-mysql-source refers to the top of MySQL source directory (which
--with-mysql-bindir refers to where MySQL binary executables (i.e. contains the VERSION file or the configure.in file), --with-mysql-bindir
mysql_config) are located, and --with-mysql-plugindir refers to a plugin refers to where MySQL binary executables (i.e. mysql_config) are located,
directory where plugin libraries (*.so) are installed. and --with-mysql-plugindir refers to a plugin directory where plugin
libraries (*.so) are installed.
$ make $ make
$ sudo make install $ sudo make install

View File

@ -93,7 +93,6 @@ The execute_single method can be used for inserting records also.
my $res = $hs->execute_single(3, '+', [ 'foo', 'bar', 'baz' ]); my $res = $hs->execute_single(3, '+', [ 'foo', 'bar', 'baz' ]);
die $hs->get_error() if $res->[0] != 0; die $hs->get_error() if $res->[0] != 0;
my $num_inserted_rows = $res->[1];
The 3rd argument must be an arrayref whose elements correspond to The 3rd argument must be an arrayref whose elements correspond to
the 5th argument for the corresponding open_index call. If there the 5th argument for the corresponding open_index call. If there
@ -116,6 +115,15 @@ executing them separatedly.
# ... # ...
} }
-----------------------------------------------------------------
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 occured, the first element of the returned When an error is occured, the first element of the returned
arrayref becomes a non-zero value. A negative value indicates arrayref becomes a non-zero value. A negative value indicates

View File

@ -29,7 +29,7 @@ Request and Response
lines) at one time, and receive responses for them at one time. lines) at one time, and receive responses for them at one time.
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
'open_index' request Opening index
The 'open_index' request has the following syntax. The 'open_index' request has the following syntax.
@ -74,23 +74,21 @@ FILETER is a sequence of the following parameters.
HandlerSocket supports '=', '>', '>=', '<', and '<='. HandlerSocket supports '=', '>', '>=', '<', and '<='.
- <vlen> indicates the length of the trailing parameters <v1> ... <vn>. This - <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 must be smaller than or equal to the number of index columns specified by
the <columns> parameter of the corresponding 'open_index' request. the <indexname> parameter of the corresponding 'open_index' request.
- <v1> ... <vn> specify the index column values to fetch. - <v1> ... <vn> specify the index column values to fetch.
- LIM is optional. <limit> and <offset> are numbers. When omitted, it works - 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. 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. 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 - IN is optional. It works like WHERE ... IN syntax of SQL. <icol> must be
smaller than or equal to the number of index columns specified by the smaller than the number of index columns specified by the <indexname>
<columns> parameter of the corresponding 'open_index' request. If IN is parameter of the corresponding 'open_index' request. If IN is specified in
specified in a find request, the <icol>-th parameter value of <v1> ... a find request, the <icol>-th parameter value of <v1> ... <vn> is ignored.
<vn> is ignored.
smaller than or equal to the number of index columns specified by the
- FILTERs are optional. A FILTER specifies a filter. <ftyp> is either 'F' - FILTERs are optional. A FILTER specifies a filter. <ftyp> is either 'F'
(filter) or 'W' (while). <fop> specifies the comparison operation to use. (filter) or 'W' (while). <fop> specifies the comparison operation to use.
<fcol> must be smaller than or equal to the number of columns specified by <fcol> must be smaller than the number of columns specified by the
the <fcolumns> parameter of the corresponding 'open_index' request. <fcolumns> parameter of the corresponding 'open_index' request. Multiple
Multiple filters can be specified, and work as the logical AND of them. filters can be specified, and work as the logical AND of them. The
The difference of 'F' and 'W' is that, when a record does not meet 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. specified condition, 'F' simply skips the record, and 'W' stops the loop.
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
@ -112,8 +110,8 @@ MOD is a sequence of the following parameters.
<mk> must be smaller than or equal to the length of <columns> specified by <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 the corresponding 'open_index' request. If <mop> is 'D', these parameters
are ignored. If <mop> is '+' or '-', values must be numeric. If <mop> is are ignored. If <mop> is '+' or '-', values must be numeric. If <mop> is
'-' and it attempts to change column values from negative to positive or '-' and it attempts to change a column value from negative to positive or
positive to negative, it is not modified. positive to negative, the column value is not modified.
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
Inserting data Inserting data
@ -187,6 +185,8 @@ syntax.
0 1 <nummod> 0 1 <nummod>
- <nummod> is the number of modified rows. - <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' Response for 'insert'
@ -196,3 +196,10 @@ syntax.
0 1 0 1
----------------------------------------------------------------------------
Response for 'auth'
If 'auth' is succeeded, HanderSocket returns a line of the following syntax.
0 1

View File

@ -8,7 +8,8 @@ HandlerSocketプラグインのビルド方法(RPMを使わない方法)
$ ./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 $ ./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のソースコードのトップディレク ここで--with-mysql-sourceにはMySQLのソースコードのトップディレク
トリを指定します。--with-mysql-bindirにはインストール済みのMySQL トリを指定します(そこにVERSIONファイルかconfigure.inファイルがなく
てはなりません)。--with-mysql-bindirにはインストール済みのMySQL
のmysql_configコマンドが有るディレクトリを指定します。 のmysql_configコマンドが有るディレクトリを指定します。
その後以下のようにビルド・インストールします。 その後以下のようにビルド・インストールします。

View File

@ -86,7 +86,6 @@ execute_singleメソッドは列の挿入にも使用できます。
my $res = $hs->execute_single(3, '+', [ 'foo', 'bar', 'baz' ]); my $res = $hs->execute_single(3, '+', [ 'foo', 'bar', 'baz' ]);
die $hs->get_error() if $res->[0] != 0; die $hs->get_error() if $res->[0] != 0;
my $num_inserted_rows = $res->[1];
第3引数は、対応するopen_index呼び出しの第5引数の列リストと同じだ 第3引数は、対応するopen_index呼び出しの第5引数の列リストと同じだ
けの長さの配列への参照でなければなりません。open_index呼び出しの けの長さの配列への参照でなければなりません。open_index呼び出しの
@ -109,6 +108,15 @@ execute_multiメソッドを使えば、複数のリクエストを一つの呼
# ... # ...
} }
-----------------------------------------------------------------
もしhandlersocketが接続を認証するように設定されている
(handlersocket_plain_secret又はhandlersocket_plain_secret_wrがセッ
トされている)ならば、クライアントは他のメソッド呼び出しの前にauth
メソッドを呼び出す必要があります。
my $res = $hs->auth('password');
die $hs->get_error() if $res->[0] != 0;
----------------------------------------------------------------- -----------------------------------------------------------------
エラーが起こると返値の配列参照の最初の要素が0以外になります。負の エラーが起こると返値の配列参照の最初の要素が0以外になります。負の
数の場合はI/Oエラーが起こったことを示し、その場合はその 数の場合はI/Oエラーが起こったことを示し、その場合はその

View File

@ -1,94 +1,180 @@
----------------------------------------------------------------- ----------------------------------------------------------------------------
handlersocketの通信プロトコル handlersocketの通信プロトコル
----------------------------------------------------------------- ----------------------------------------------------------------------------
構文 基本的な構文
コマンド行は改行(LF)で終わる。 HandlerSocketのプロトコルは行ベース。各行は改行文字(0x0a)で終わる。
コマンド行は複数のトークンからなり、トークン間はTABで区切られる。 行は複数のトークンからなり、トークン間はTAB文字(0x09)で区切られる。
・トークンはNULLトークンか、文字列トークンのいずれか。 ・トークンはNULLトークンか、文字列トークンのいずれか。
・NULLトークンは単一のNUL文字であらわされる。 ・NULLトークンは単一のNUL文字(0x00)であらわされる。
・文字列トークンは、0バイト以上の文字列であらわされる。ただし0x10 ・文字列トークンは、0バイト以上の文字列であらわされる。ただし0x10未満の文字
未満の文字については0x01を前置し、0x40を加えたコードであらわさ については0x01を前置し、0x40を加えたコードであらわされる。それ以外の文字は
れる。それ以外の文字はその文字自身のコードであらわされる。 その文字自身のコードであらわされる。
----------------------------------------------------------------- ----------------------------------------------------------------------------
リクエストとレスポンス リクエストとレスポンス
・接続が確立した直後の状態では、まずクライアントがコマンド行を送 ・HandlerSocketのプロトコルは単純なリクエスト・レスポンスプロトコルになって
る。(リクエスト) いる。接続が確立した後は、まずクライアントがリクエストを送る。
・サーバはクライアントが送ったリクエストと丁度同じ数のコマンド行 ・サーバは、クライアントが送ったリクエストと丁度同じ数の行(レスポンス)を返
を返す。(レスポンス) す。
・リクエストはパイプライン化してよい。つまりクライアントは前に ・リクエストはパイプライン化してよい。つまりクライアントは前に送ったリクエス
送ったリクエストに対する返事を待たずに次のリクエストを送っても トに対する返事(レスポンス)を待たずに次のリクエストを送ってもよい。
よい。
----------------------------------------------------------------- ----------------------------------------------------------------------------
リクエスト インデックスを開く
・open_index命令は次のような構文を持つ。 open_index命令は次のような構文を持つ。
'P' indexid dbname tablename indexname fieldlist
indexidは開いている索引に付けられる番号で、同一接続上で後に実行
する命令の、対象索引を指定するために使われる。dbname、tablename、
indexnameはそれぞれ開きたいDB、テーブル、索引の名前。索引の名前
として"PRIMARY"を指定するとプライマリキーが開かれる。fieldlist
はカンマ区切りの列名のリスト。
・find命令は次のような構文を持つ。
indexid op nflds v1 ... vn limit offset
indexidは実行対象の索引を指定する。opは索引検索の演算子(後述)。
v1からvnは可変長で、その個数はnflds。nfldsはindexidで指定された
open_index命令のindexnameの索引のfieldlistのフィールド数に等し
いか小さくなくてはならない。m2からmkは可変長で、その個数は
indexidで指定されたopen_index命令が発行された際のfieldlistに一
致しなければならない。コマンド行のlimit以降は省略できる。limit
とoffsetは、検索条件に合致する列のうちレスポンスに返す列数の上
限と、スキップする列数。limitとoffsetを省略した場合はそれぞれ1
と0が指定されたときと同じ動作をする。find命令はレスポンスとして、
条件に合致した列のリストを返す。opとして指定できる演算子は次の
とおり。
'=' - v1 ... vnと一致するものを取得
'>' - v1 ... vnより大きいものを昇順に取得
'>=' - v1 ... vnに一致するか大きいものを昇順に取得
'<' - v1 ... vnより小さいものを降順に取得
'<=' - v1 ... vnに一致するか等しいものを降順に取得
nfldsが1より大きい(v1 ... vnが2個以上)ときは辞書式順序で比較さ
れる。
・find_modify命令は次のような構文を持つ。
indexid op nflds v1 ... vn limit offset modop m1 ... mk
modopより前の部分はfind命令と同等で、これによって操作対象の行を
指定する。その操作対象の行に対しmodopで指定された変更処理を実行
する。m1 ... mkは可変長で、省略できる。modopは次いずれか。
'U' - indexidで指定されたopen_index命令のfieldlist列
の内容を、m1 ... mkの値で更新する。
'D' - 対象の行を削除する。m1 ... mkの値は無視される。
・insert命令はのような構文を持つ。
indexid '+' nflds v1 ... vn
indexidで指定されたテーブルに、列を挿入する。v1 ... vnは可変長
で、その個数はnflds。nfldsはindexidで指定されたopen_index命令の
indexnameの索引のfieldlistのフィールド数に等しいか小さくなくて
はならない。
----------------------------------------------------------------- P <indexid> <dbname> <tablename> <indexname> <columns> [<fcolumns>]
レスポンス
・open_index命令が成功したとき、レスポンスは次の構文を持つ。 - <indexid>は数字で、同一接続上で後に実行する命令の、対象索引を指定するため
'0' '1' に使われる。
・find命令が成功したとき、レスポンスは次の構文を持つ。 - <dbname>, <tablename>, <indexname>は文字列で、それぞれDB名、テーブル名、
'0' nflds v1 ... vn 索引の名前を指定する。<indexname>として「PRIMARY」を指定するとプライマリ
nfldsは結果セットの列の数をあらわす。v1 ... vnは可変長で、その キーが開かれる。
長さはnfldsの整数倍。v1 ... vnは空のこともあり、それは条件に合 - <columns>はカンマ区切りの列名のリスト。
致するレコードが存在しなかったことをあらわす。結果セットが複数 - <fcolumns>はカンマ区切りの列名のリスト。これは省略することができる。
行になったときはv1 ... vnの長さがnfldsの2倍以上となり、最初の
行から順にv1 ... vnにセットされる。 このopen_index命令が実行されると、HandlerSocketプラグインは指定されたDB、
・modify命令が成功したとき、レスポンスは次の構文を持つ。 テーブル、索引を開く。開かれた索引は接続が閉じられるまで開かれたままになる。
'0' '1' nummod 開かれた索引は<indexid>の数字で識別される。もし既に<indexid>に指定された番号
nummodは変更が施された行数。nummodが0のときは変更された行が無 の索引が既に開かれている場合は古いほうが閉じられる。この<indexid>はなるべく
かったことをあらわす。 小さな数字を使ったほうが効率が良い。
・insert命令が成功したとき、レスポンスは次の構文を持つ。
'0' '1' ----------------------------------------------------------------------------
・命令が失敗したとき、レスポンスは命令に関わらず次の構文を持つ。 データ取得
err '1' message
errは0以外の数値で、エラーコードをあらわす。messageは人間可読な find命令は次のような構文を持つ。
エラーメッセージ。ただしmessageが無いこともある。
<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

View File

@ -658,7 +658,7 @@ dbcontext::cmd_insert_internal(dbcallback_i& cb, const prep_stmt& pst,
empty_record(table); empty_record(table);
memset(buf, 0, table->s->null_bytes); /* clear null flags */ memset(buf, 0, table->s->null_bytes); /* clear null flags */
const prep_stmt::fields_type& rf = pst.get_ret_fields(); const prep_stmt::fields_type& rf = pst.get_ret_fields();
const size_t n = rf.size(); const size_t n = std::min(rf.size(), fvalslen);
for (size_t i = 0; i < n; ++i) { for (size_t i = 0; i < n; ++i) {
uint32_t fn = rf[i]; uint32_t fn = rf[i];
Field *const fld = table->field[fn]; Field *const fld = table->field[fn];

View File

@ -151,7 +151,7 @@ sv_get_string_ref(SV *sv)
static IV static IV
sv_get_iv(SV *sv) sv_get_iv(SV *sv)
{ {
if (sv == 0 || !SvIOK(sv)) { if (sv == 0 || ( !SvIOK(sv) && !SvPOK(sv) ) ) {
return 0; return 0;
} }
return SvIV(sv); return SvIV(sv);

View File

@ -1,6 +1,6 @@
#!/bin/bash #!/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"; 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 source ../common/compat.sh

View File

@ -27,7 +27,7 @@ srand(999);
my %valmap = (); my %valmap = ();
my $sth = $dbh->prepare("insert into $table values (?,?,?)"); my $sth = $dbh->prepare("insert ignore into $table values (?,?,?)");
for (my $i = 0; $i < $tablesize; ++$i) { for (my $i = 0; $i < $tablesize; ++$i) {
my $k = $i; my $k = $i;
my ($s1, $s2) = ("", ""); my ($s1, $s2) = ("", "");

View File

@ -60,7 +60,7 @@ sub test_one {
$dbh->do( $dbh->do(
"create table $table (" . "create table $table (" .
"k $typ, " . "k $typ, " .
"v1 varchar(2047), " . "v1 varchar(1000), " .
"v2 $typ, " . "v2 $typ, " .
"primary key(k$keylen_str), " . "primary key(k$keylen_str), " .
"index i1(v1), index i2(v2$keylen_str, v1(300))) " . "index i1(v1), index i2(v2$keylen_str, v1(300))) " .

View File

@ -113,7 +113,7 @@ sub test_one {
"(k1 int not null, k2 int not null, " . "(k1 int not null, k2 int not null, " .
"v1 int not null, v2 $typ default null, " . "v1 int not null, v2 $typ default null, " .
"primary key (k1, k2) ) engine = innodb"); "primary key (k1, k2) ) engine = innodb");
my $sth = $dbh->prepare("insert into $table values (?,?,?,?)"); my $sth = $dbh->prepare("insert ignore into $table values (?,?,?,?)");
for (my $i = 0; $i < $tablesize; ++$i) { for (my $i = 0; $i < $tablesize; ++$i) {
my $j = 0; my $j = 0;
for my $v (@$values) { for my $v (@$values) {

View File

@ -0,0 +1,2 @@
HS
0 0

View File

@ -0,0 +1,35 @@
#!/usr/bin/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";