123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347 |
- -module(epgsql_copy_SUITE).
- -include_lib("common_test/include/ct.hrl").
- -include_lib("stdlib/include/assert.hrl").
- -include("epgsql.hrl").
- -export([
- init_per_suite/1,
- all/0,
- end_per_suite/1,
- from_stdin_text/1,
- from_stdin_csv/1,
- from_stdin_binary/1,
- from_stdin_io_apis/1,
- from_stdin_with_terminator/1,
- from_stdin_corrupt_data/1
- ]).
- init_per_suite(Config) ->
- [{module, epgsql}|Config].
- end_per_suite(_Config) ->
- ok.
- all() ->
- [
- from_stdin_text,
- from_stdin_csv,
- from_stdin_binary,
- from_stdin_io_apis,
- from_stdin_with_terminator,
- from_stdin_corrupt_data
- ].
- %% @doc Test that COPY in text format works
- from_stdin_text(Config) ->
- Module = ?config(module, Config),
- epgsql_ct:with_connection(
- Config,
- fun(C) ->
- ?assertEqual(
- {ok, [text, text]},
- Module:copy_from_stdin(
- C, "COPY test_table1 (id, value) FROM STDIN WITH (FORMAT text)")),
- ?assertEqual(
- ok,
- io:put_chars(C,
- "10\thello world\n"
- "11\t\\N\n"
- "12\tline 12\n")),
- ?assertEqual(
- ok,
- io:put_chars(C, "13\tline 13\n")),
- ?assertEqual(
- ok,
- io:put_chars(C, "14\tli")),
- ?assertEqual(
- ok,
- io:put_chars(C, "ne 14\n")),
- ?assertEqual(
- {ok, 5},
- Module:copy_done(C)),
- ?assertMatch(
- {ok, _, [{10, <<"hello world">>},
- {11, null},
- {12, <<"line 12">>},
- {13, <<"line 13">>},
- {14, <<"line 14">>}]},
- Module:equery(C,
- "SELECT id, value FROM test_table1"
- " WHERE id IN (10, 11, 12, 13, 14) ORDER BY id"))
- end).
- %% @doc Test that COPY in CSV format works
- from_stdin_csv(Config) ->
- Module = ?config(module, Config),
- epgsql_ct:with_connection(
- Config,
- fun(C) ->
- ?assertEqual(
- {ok, [text, text]},
- Module:copy_from_stdin(
- C, "COPY test_table1 (id, value) FROM STDIN WITH (FORMAT csv, QUOTE '''')")),
- ?assertEqual(
- ok,
- io:put_chars(C,
- "20,'hello world'\n"
- "21,\n"
- "22,line 22\n")),
- ?assertEqual(
- ok,
- io:put_chars(C, "23,'line 23'\n")),
- ?assertEqual(
- ok,
- io:put_chars(C, "24,'li")),
- ?assertEqual(
- ok,
- io:put_chars(C, "ne 24'\n")),
- ?assertEqual(
- {ok, 5},
- Module:copy_done(C)),
- ?assertMatch(
- {ok, _, [{20, <<"hello world">>},
- {21, null},
- {22, <<"line 22">>},
- {23, <<"line 23">>},
- {24, <<"line 24">>}]},
- Module:equery(C,
- "SELECT id, value FROM test_table1"
- " WHERE id IN (20, 21, 22, 23, 24) ORDER BY id"))
- end).
- %% @doc Test that COPY in binary format works
- from_stdin_binary(Config) ->
- Module = ?config(module, Config),
- epgsql_ct:with_connection(
- Config,
- fun(C) ->
- ?assertEqual(
- {ok, [binary, binary]},
- Module:copy_from_stdin(
- C, "COPY test_table1 (id, value) FROM STDIN WITH (FORMAT binary)",
- {binary, [int4, text]})),
- %% Batch of rows
- ?assertEqual(
- ok,
- Module:copy_send_rows(
- C,
- [{60, <<"hello world">>},
- {61, null},
- {62, "line 62"}],
- 5000)),
- %% Single row
- ?assertEqual(
- ok,
- Module:copy_send_rows(
- C,
- [{63, <<"line 63">>}],
- 1000)),
- %% Rows as lists
- ?assertEqual(
- ok,
- Module:copy_send_rows(
- C,
- [
- [64, <<"line 64">>],
- [65, <<"line 65">>]
- ],
- infinity)),
- ?assertEqual({ok, 6}, Module:copy_done(C)),
- ?assertMatch(
- {ok, _, [{60, <<"hello world">>},
- {61, null},
- {62, <<"line 62">>},
- {63, <<"line 63">>},
- {64, <<"line 64">>},
- {65, <<"line 65">>}]},
- Module:equery(C,
- "SELECT id, value FROM test_table1"
- " WHERE id IN (60, 61, 62, 63, 64, 65) ORDER BY id"))
- end).
- %% @doc Tests that different IO-protocol APIs work
- from_stdin_io_apis(Config) ->
- Module = ?config(module, Config),
- epgsql_ct:with_connection(
- Config,
- fun(C) ->
- ?assertEqual(
- {ok, [text, text]},
- Module:copy_from_stdin(
- C, "COPY test_table1 (id, value) FROM STDIN WITH (FORMAT text)")),
- ?assertEqual(ok, io:format(C, "30\thello world\n", [])),
- ?assertEqual(ok, io:format(C, "~b\t~s\n", [31, "line 31"])),
- %% Output "32\thello\n" in multiple calls
- ?assertEqual(ok, io:write(C, 32)),
- ?assertEqual(ok, io:put_chars(C, "\t")),
- ?assertEqual(ok, io:write(C, hello)),
- ?assertEqual(ok, io:nl(C)),
- %% Using `file` API
- ?assertEqual(ok, file:write(C, "33\tline 33\n34\tline 34\n")),
- %% Binary
- ?assertEqual(ok, io:put_chars(C, <<"35\tline 35\n">>)),
- ?assertEqual(ok, file:write(C, <<"36\tline 36\n">>)),
- %% IoData
- ?assertEqual(ok, io:put_chars(C, [<<"37">>, $\t, <<"line 37">>, <<$\n>>])),
- ?assertEqual(ok, file:write(C, [["38", <<$\t>>], [<<"line 38">>, $\n]])),
- %% Raw IO-protocol message-passing
- Ref = erlang:make_ref(),
- C ! {io_request, self(), Ref, {put_chars, unicode, "39\tline 39\n"}},
- ?assertEqual(ok, receive {io_reply, Ref, Resp} -> Resp
- after 5000 ->
- timeout
- end),
- %% Not documented!
- ?assertEqual(ok, io:requests(
- C,
- [{put_chars, unicode, "40\tline 40\n"},
- {put_chars, latin1, "41\tline 41\n"},
- {format, "~w\t~s", [42, "line 42"]},
- nl])),
- ?assertEqual(
- {ok, 13},
- Module:copy_done(C)),
- ?assertMatch(
- {ok, _, [{30, <<"hello world">>},
- {31, <<"line 31">>},
- {32, <<"hello">>},
- {33, <<"line 33">>},
- {34, <<"line 34">>},
- {35, <<"line 35">>},
- {36, <<"line 36">>},
- {37, <<"line 37">>},
- {38, <<"line 38">>},
- {39, <<"line 39">>},
- {40, <<"line 40">>},
- {41, <<"line 41">>},
- {42, <<"line 42">>}
- ]},
- Module:equery(
- C,
- "SELECT id, value FROM test_table1"
- " WHERE id IN (30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42)"
- " ORDER BY id"))
- end).
- %% @doc Tests that "end-of-data" terminator is successfully ignored
- from_stdin_with_terminator(Config) ->
- Module = ?config(module, Config),
- epgsql_ct:with_connection(
- Config,
- fun(C) ->
- %% TEXT
- ?assertEqual(
- {ok, [text, text]},
- Module:copy_from_stdin(
- C, "COPY test_table1 (id, value) FROM STDIN WITH (FORMAT text)")),
- ?assertEqual(ok, io:put_chars(
- C,
- "50\tline 50\n"
- "51\tline 51\n"
- "\\.\n")),
- ?assertEqual({ok, 2}, Module:copy_done(C)),
- %% CSV
- ?assertEqual(
- {ok, [text, text]},
- Module:copy_from_stdin(
- C, "COPY test_table1 (id, value) FROM STDIN WITH (FORMAT csv)")),
- ?assertEqual(ok, io:put_chars(
- C,
- "52,line 52\n"
- "53,line 53\n"
- "\\.\n")),
- ?assertEqual({ok, 2}, Module:copy_done(C)),
- ?assertMatch(
- {ok, _, [{50, <<"line 50">>},
- {51, <<"line 51">>},
- {52, <<"line 52">>},
- {53, <<"line 53">>}
- ]},
- Module:equery(C,
- "SELECT id, value FROM test_table1"
- " WHERE id IN (50, 51, 52, 53) ORDER BY id"))
- end).
- from_stdin_corrupt_data(Config) ->
- Module = ?config(module, Config),
- epgsql_ct:with_connection(
- Config,
- fun(C) ->
- ?assertEqual(
- {ok, [text, text]},
- Module:copy_from_stdin(
- C, "COPY test_table1 (id, value) FROM STDIN WITH (FORMAT text)")),
- %% Wrong number of arguments to io:format
- Fmt = "~w\t~s\n",
- ?assertMatch({error, {fun_exception, {error, badarg, _Stack}}},
- io:request(C, {format, Fmt, []})),
- ?assertError(badarg, io:format(C, Fmt, [])),
- %% Wrong return value from IO function
- ?assertEqual({error, {fun_return_not_characters, node()}},
- io:request(C, {put_chars, unicode, erlang, node, []})),
- ?assertEqual({ok, 0}, Module:copy_done(C)),
- %%
- %% Corrupt text format
- ?assertEqual(
- {ok, [text, text]},
- Module:copy_from_stdin(
- C, "COPY test_table1 (id, value) FROM STDIN WITH (FORMAT text)")),
- ?assertEqual(ok, io:put_chars(
- C,
- "42\n43\nwasd\n")),
- ?assertMatch(
- #error{codename = bad_copy_file_format,
- severity = error},
- receive
- {epgsql, C, {error, Err}} ->
- Err
- after 5000 ->
- timeout
- end),
- ?assertEqual({error, not_in_copy_mode},
- io:request(C, {put_chars, unicode, "queque\n"})),
- ?assertError(badarg, io:format(C, "~w\n~s\n", [60, "wasd"])),
- %%
- %% Corrupt CSV format
- ?assertEqual(
- {ok, [text, text]},
- Module:copy_from_stdin(
- C, "COPY test_table1 (id, value) FROM STDIN WITH (FORMAT csv)")),
- ?assertEqual(ok, io:put_chars(
- C,
- "42\n43\nwasd\n")),
- ?assertMatch(
- #error{codename = bad_copy_file_format,
- severity = error},
- receive
- {epgsql, C, {error, Err}} ->
- Err
- after 5000 ->
- timeout
- end),
- %%
- %% Corrupt binary format
- ?assertEqual(
- {ok, [binary, binary]},
- Module:copy_from_stdin(
- C, "COPY test_table1 (id, value) FROM STDIN WITH (FORMAT binary)",
- {binary, [int4, text]})),
- ?assertEqual(
- ok,
- Module:copy_send_rows(C, [{44, <<"line 44">>}], 1000)),
- ?assertEqual(ok, io:put_chars(C, "45\tThis is not ok!\n")),
- ?assertMatch(
- #error{codename = bad_copy_file_format,
- severity = error},
- receive
- {epgsql, C, {error, Err}} ->
- Err
- after 5000 ->
- timeout
- end),
- %% Connection is still usable
- ?assertMatch(
- {ok, _, [{1}]},
- Module:equery(C, "SELECT 1", []))
- end).
|