diff --git a/src/binary.cpp b/src/binary.cpp index c57d2d11..dbc13424 100644 --- a/src/binary.cpp +++ b/src/binary.cpp @@ -288,98 +288,69 @@ static Oid get_corr_postgres_type(const TypeRef & type) void ch_binary_insert_state_free(void * c) { auto * state = (ch_binary_insert_state *)c; - if (state->columns) + if (state->insert_block) { - /* try to send empty block that sets proper ClickHouse state */ - if (!state->success) + /* Finish the insert to set the proper ClickHouse state */ + Client * client = (Client *)state->conn->client; + try { - try - { - Client * client = (Client *)state->conn->client; - client->Insert(state->table_name, Block()); - } - catch (const std::exception & e) - { - // just ignore, next query will fail - elog(NOTICE, "pg_clickhouse: could not send empty packet"); - } + client->EndInsert(); } - - delete (std::vector *)state->columns; + catch (const std::exception & e) + { + // just ignore, next query will fail + elog(NOTICE, "pg_clickhouse: could not finish INSERT: - %s", e.what()); + } + delete (Block *)state->insert_block; } } void ch_binary_prepare_insert(void * conn, char * query, ch_binary_insert_state * state) { - throw std::runtime_error("clickhouse_fdw: XXX ch_binary_prepare_insert not implemented"); - -// std::vector * vec = nullptr; -// Client * client = (Client *)((ch_binary_connection_t *)conn)->client; - -// try -// { -// client->PrepareInsert( -// std::string(query) + " VALUES", [&state, &vec](const Block & sample_block) { -// if (sample_block.GetColumnCount() == 0) -// return true; - -// vec = new std::vector(); - -// state->len = sample_block.GetColumnCount(); - -// #if PG_VERSION_NUM < 120000 -// state->outdesc = CreateTemplateTupleDesc(state->len, false); -// #else -// state->outdesc = CreateTemplateTupleDesc(state->len); -// #endif - -// for (size_t i = 0; i < state->len; i++) -// { -// bool error = false; -// clickhouse::ColumnRef col = sample_block[i]; - -// auto chtype = col->Type(); -// if (chtype->GetCode() == Type::LowCardinality) -// { -// chtype = col->As()->GetNestedType(); -// } - -// Oid pg_type = get_corr_postgres_type(chtype); - -// vec->push_back(clickhouse::CreateColumnByType(col->Type()->GetName())); -// const char * colname = sample_block.GetColumnName(i).c_str(); - -// /* we can't afford long jumps outside of this function */ -// PG_TRY(); -// { -// TupleDescInitEntry( -// state->outdesc, (AttrNumber)i + 1, colname, pg_type, -1, 0); -// } -// PG_CATCH(); -// { -// error = true; -// } -// PG_END_TRY(); - -// if (error) -// throw std::runtime_error("could not init tuple descriptor"); -// } - -// return true; -// }); -// } -// catch (const std::exception & e) -// { -// client->ResetConnection(); - -// if (vec != nullptr) -// delete vec; - -// elog(ERROR, "clickhouse_fdw: error while insert preparation - %s", e.what()); -// } - -// if (vec != nullptr) -// state->columns = (void *)vec; + // Start the INSERT. + Block * block; + Client * client = (Client *)((ch_binary_connection_t *)conn)->client; + try + { + block = new Block(client->BeginInsert(std::string(query) + " VALUES")); + } + catch (const std::exception & e) + { + elog(ERROR, "pg_clickhouse: could not prepare insert - %s", e.what()); + } + + // Setup the column config (or return if no columns). + state->len = block->GetColumnCount(); + if (state->len == 0) + { + delete block; + return; + } + state->outdesc = CreateTemplateTupleDesc(state->len); + + // Iterate over the list of columns returned by ClickHouse. + AttrNumber i = 0; + for (Block::Iterator bi(*block); bi.IsValid(); bi.Next()) + { + // Determine the Postgres column type. + Oid pg_type = get_corr_postgres_type(bi.Type()); + const char * colname = bi.Name().c_str(); + + PG_TRY(); + { + TupleDescInitEntry(state->outdesc, ++i, colname, pg_type, -1, 0); + } + PG_CATCH(); + { + // Clean up and re-throw. + client->ResetConnection(); + delete block; + PG_RE_THROW(); + } + PG_END_TRY(); + } + + state->insert_block = (ch_insert_block_h *) block; } static void column_append(clickhouse::ColumnRef col, Datum val, Oid valtype, bool isnull) @@ -507,14 +478,7 @@ static void column_append(clickhouse::ColumnRef col, Datum val, Oid valtype, boo col->As()->Append(s); break; case Type::Code::LowCardinality: { - // XXX Figure out proper value to create and pass to - // Append. - throw std::runtime_error( - "clickhouse_fdw: XXX unsupported column type " - + col->Type()->GetName() - ); - // auto item = ItemView{Type::String, std::string_view(s)}; - // col->As()->Append(item); + col->AsStrict>()->Append(s); break; } default: @@ -570,25 +534,19 @@ static void column_append(clickhouse::ColumnRef col, Datum val, Oid valtype, boo break; } case ANYARRAYOID: { - // auto arr = (ch_binary_array_t *)DatumGetPointer(val); - switch (col->Type()->GetCode()) { case Type::Array: { - // XXX Figure out proper value to create and pass to - // Append. - throw std::runtime_error( - "clickhouse_fdw: XXX unsupported column type " - + col->Type()->GetName() + auto arrcol = col->AsStrict(); + auto items = CreateColumnByType( + arrcol->GetType().As()->GetItemType()->GetName() ); - // auto arrcol = col->As(); - - // arrcol->OffsetsIncrease(arr->len); - // for (size_t i = 0; i < arr->len; i++) - // column_append( - // arrcol->Nested(), arr->datums[i], arr->item_type, arr->nulls[i]); + auto arr = (ch_binary_array_t *)DatumGetPointer(val); + for (size_t i = 0; i < arr->len; i++) + column_append(items, arr->datums[i], arr->item_type, arr->nulls[i]); - // break; + arrcol->AppendAsColumn(items); + break; } default: throw std::runtime_error( @@ -610,8 +568,8 @@ void ch_binary_column_append_data(ch_binary_insert_state * state, size_t colidx) { try { - auto columns = *(std::vector *)state->columns; - auto col = columns[colidx]; + auto block = (Block *)state->insert_block; + auto col = (*block)[colidx]; Datum val = state->values[colidx]; Oid valtype = TupleDescAttr(state->outdesc, colidx)->atttypid; @@ -629,16 +587,11 @@ void ch_binary_insert_columns(ch_binary_insert_state * state) { try { - Block block; - auto columns = *(std::vector *)state->columns; - for (int i = 0; i < state->outdesc->natts; ++i) - { - Form_pg_attribute att = TupleDescAttr(state->outdesc, i); - block.AppendColumn(NameStr(att->attname), columns[i]); - } - Client * client = (Client *)state->conn->client; - client->Insert(state->table_name, block); + auto block = (Block *)state->insert_block; + block->RefreshRowCount(); + client->SendInsertBlock(*block); + block->Clear(); } catch (const std::exception & e) { diff --git a/src/include/binary.hh b/src/include/binary.hh index 6cb466b0..6f213832 100644 --- a/src/include/binary.hh +++ b/src/include/binary.hh @@ -6,6 +6,7 @@ extern "C" { #endif typedef struct ch_binary_connection_t ch_binary_connection_t; +typedef struct ch_insert_block_h ch_insert_block_h; typedef struct ch_binary_response_t { void *values; @@ -48,7 +49,7 @@ typedef struct { MemoryContextCallback callback; TupleDesc outdesc; - void *columns; /* std::vector */ + ch_insert_block_h *insert_block; /* clickhouse::Block */ size_t len; void *conversion_states; char *table_name; diff --git a/src/pglink.c b/src/pglink.c index 0bfcdc14..2a0d948b 100644 --- a/src/pglink.c +++ b/src/pglink.c @@ -737,7 +737,6 @@ binary_insert_tuple(void *istate, TupleTableSlot *slot) else { ch_binary_insert_columns(state); - state->success = true; } } diff --git a/test/expected/binary_inserts.out b/test/expected/binary_inserts.out new file mode 100644 index 00000000..19832d94 --- /dev/null +++ b/test/expected/binary_inserts.out @@ -0,0 +1,237 @@ +SET datestyle = 'ISO'; +CREATE SERVER binary_inserts_loopback FOREIGN DATA WRAPPER clickhouse_fdw OPTIONS(dbname 'binary_inserts_test', driver 'binary'); +CREATE USER MAPPING FOR CURRENT_USER SERVER binary_inserts_loopback; +SELECT clickhouse_raw_query('drop database if exists binary_inserts_test'); + clickhouse_raw_query +---------------------- + +(1 row) + +SELECT clickhouse_raw_query('create database binary_inserts_test'); + clickhouse_raw_query +---------------------- + +(1 row) + +SELECT clickhouse_raw_query('CREATE TABLE binary_inserts_test.ints ( + c1 Int8, c2 Int16, c3 Int32, c4 Int64 +) ENGINE = MergeTree PARTITION BY c1 ORDER BY (c1); +'); + clickhouse_raw_query +---------------------- + +(1 row) + +SELECT clickhouse_raw_query('CREATE TABLE binary_inserts_test.uints ( + c1 UInt8, c2 UInt16, c3 UInt32, c4 UInt64 +) ENGINE = MergeTree PARTITION BY c1 ORDER BY (c1); +'); + clickhouse_raw_query +---------------------- + +(1 row) + +SELECT clickhouse_raw_query('CREATE TABLE binary_inserts_test.floats ( + c1 Float32, c2 Float64 +) ENGINE = MergeTree PARTITION BY c1 ORDER BY (c1) SETTINGS allow_floating_point_partition_key=1; +'); + clickhouse_raw_query +---------------------- + +(1 row) + +SELECT clickhouse_raw_query('CREATE TABLE binary_inserts_test.null_ints ( + c1 Int8, c2 Nullable(Int32) +) ENGINE = MergeTree PARTITION BY c1 ORDER BY (c1); +'); + clickhouse_raw_query +---------------------- + +(1 row) + +SELECT clickhouse_raw_query('CREATE TABLE binary_inserts_test.complex ( + c1 Int32, c2 Date, c3 DateTime, c4 String, c5 FixedString(10), c6 LowCardinality(String), c7 DateTime64(3) +) ENGINE = MergeTree PARTITION BY c1 ORDER BY (c1); +'); + clickhouse_raw_query +---------------------- + +(1 row) + +SELECT clickhouse_raw_query('CREATE TABLE binary_inserts_test.arrays ( + c1 Int32, c2 Array(Int32) +) ENGINE = MergeTree PARTITION BY c1 ORDER BY (c1); +'); + clickhouse_raw_query +---------------------- + +(1 row) + +IMPORT FOREIGN SCHEMA "binary_inserts_test" FROM SERVER binary_inserts_loopback INTO public; +NOTICE: pg_clickhouse: ClickHouse type was translated to type for column "c1", change it to BOOLEAN if needed +/* ints */ +INSERT INTO ints + SELECT i, i + 1, i + 2, i+ 3 FROM generate_series(1, 3) i; +SELECT * FROM ints ORDER BY c1; + c1 | c2 | c3 | c4 +----+----+----+---- + 1 | 2 | 3 | 4 + 2 | 3 | 4 | 5 + 3 | 4 | 5 | 6 +(3 rows) + +INSERT INTO ints (c1, c4, c3, c2) + SELECT i, i + 1, i + 2, i+ 3 FROM generate_series(4, 6) i; +SELECT * FROM ints ORDER BY c1; + c1 | c2 | c3 | c4 +----+----+----+---- + 1 | 2 | 3 | 4 + 2 | 3 | 4 | 5 + 3 | 4 | 5 | 6 + 4 | 7 | 6 | 5 + 5 | 8 | 7 | 6 + 6 | 9 | 8 | 7 +(6 rows) + +/* check dropping columns (that will change attnums) */ +ALTER TABLE ints DROP COLUMN c1; +ALTER TABLE ints ADD COLUMN c1 SMALLINT; +INSERT INTO ints (c1, c2, c3, c4) + SELECT i, i + 1, i + 2, i+ 3 FROM generate_series(7, 8) i; +SELECT c1, c2, c3, c4 FROM ints ORDER BY c1; + c1 | c2 | c3 | c4 +----+----+----+---- + 1 | 2 | 3 | 4 + 2 | 3 | 4 | 5 + 3 | 4 | 5 | 6 + 4 | 7 | 6 | 5 + 5 | 8 | 7 | 6 + 6 | 9 | 8 | 7 + 7 | 8 | 9 | 10 + 8 | 9 | 10 | 11 +(8 rows) + +/* check other number types */ +INSERT INTO uints + SELECT i, i + 1, i + 2, i+ 3 FROM generate_series(1, 3) i; +SELECT * FROM uints ORDER BY c1; + c1 | c2 | c3 | c4 +----+----+----+---- + 1 | 2 | 3 | 4 + 2 | 3 | 4 | 5 + 3 | 4 | 5 | 6 +(3 rows) + +INSERT INTO floats + SELECT i * 1.1, i + 2.1 FROM generate_series(1, 3) i; +SELECT * FROM floats ORDER BY c1; + c1 | c2 +-----+----- + 1.1 | 3.1 + 2.2 | 4.1 + 3.3 | 5.1 +(3 rows) + +/* check nullable */ +INSERT INTO null_ints SELECT i, case WHEN i % 2 = 0 THEN NULL ELSE i END FROM generate_series(1, 10) i; +INSERT INTO null_ints(c1) SELECT i FROM generate_series(11, 13) i; +SELECT * FROM null_ints ORDER BY c1; + c1 | c2 +----+---- + 1 | 1 + 2 | + 3 | 3 + 4 | + 5 | 5 + 6 | + 7 | 7 + 8 | + 9 | 9 + 10 | + 11 | + 12 | + 13 | +(13 rows) + +SELECT * FROM null_ints ORDER BY c1; + c1 | c2 +----+---- + 1 | 1 + 2 | + 3 | 3 + 4 | + 5 | 5 + 6 | + 7 | 7 + 8 | + 9 | 9 + 10 | + 11 | + 12 | + 13 | +(13 rows) + +/* check dates and strings */ +ALTER TABLE complex ALTER COLUMN c7 SET DATA TYPE timestamp(3); +\d+ complex + Foreign table "public.complex" + Column | Type | Collation | Nullable | Default | FDW options | Storage | Stats target | Description +--------+--------------------------------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | integer | | not null | | | plain | | + c2 | date | | not null | | | plain | | + c3 | timestamp without time zone | | not null | | | plain | | + c4 | text | | not null | | | extended | | + c5 | character varying(10) | | not null | | | extended | | + c6 | text | | not null | | | extended | | + c7 | timestamp(3) without time zone | | not null | | | plain | | +Not-null constraints: + "complex_c1_not_null" NOT NULL "c1" + "complex_c2_not_null" NOT NULL "c2" + "complex_c3_not_null" NOT NULL "c3" + "complex_c4_not_null" NOT NULL "c4" + "complex_c5_not_null" NOT NULL "c5" + "complex_c6_not_null" NOT NULL "c6" + "complex_c7_not_null" NOT NULL "c7" +Server: binary_inserts_loopback +FDW options: (database 'binary_inserts_test', table_name 'complex', engine 'MergeTree') + +INSERT INTO complex VALUES + (1, '2020-06-01', '2020-06-02 10:01:02', 't1', 'fix_t1', 'low1', '2020-06-02 10:01:02.123'), + (2, '2020-06-02', '2020-06-03 10:01:02', 5, 'fix_t2', 'low2', '2020-06-03 11:01:02.234'), + (3, '2020-06-03', '2020-06-04 10:01:02', 5, 'fix_t3', 'low3', '2020-06-04 12:01:02'); +SELECT * FROM complex ORDER BY c1; + c1 | c2 | c3 | c4 | c5 | c6 | c7 +----+------------+---------------------+----+--------+------+---------------------------- + 1 | 2020-06-01 | 2020-06-02 10:01:02 | t1 | fix_t1 | low1 | 2020-06-02 10:01:02.122999 + 2 | 2020-06-02 | 2020-06-03 10:01:02 | 5 | fix_t2 | low2 | 2020-06-03 11:01:02.234 + 3 | 2020-06-03 | 2020-06-04 10:01:02 | 5 | fix_t3 | low3 | 2020-06-04 12:01:02 +(3 rows) + +/* check arrays */ +INSERT INTO arrays VALUES + (1, ARRAY[1,2]), + (2, ARRAY[3,4,5]), + (3, ARRAY[6,4]); +SELECT * FROM arrays ORDER BY c1; + c1 | c2 +----+--------- + 1 | {1,2} + 2 | {3,4,5} + 3 | {6,4} +(3 rows) + +DROP USER MAPPING FOR CURRENT_USER SERVER binary_inserts_loopback; +SELECT clickhouse_raw_query('DROP DATABASE binary_inserts_test'); + clickhouse_raw_query +---------------------- + +(1 row) + +DROP SERVER binary_inserts_loopback CASCADE; +NOTICE: drop cascades to 6 other objects +DETAIL: drop cascades to foreign table arrays +drop cascades to foreign table complex +drop cascades to foreign table floats +drop cascades to foreign table ints +drop cascades to foreign table null_ints +drop cascades to foreign table uints diff --git a/test/expected/binary_inserts_1.out b/test/expected/binary_inserts_1.out new file mode 100644 index 00000000..bb40eaeb --- /dev/null +++ b/test/expected/binary_inserts_1.out @@ -0,0 +1,229 @@ +SET datestyle = 'ISO'; +CREATE SERVER binary_inserts_loopback FOREIGN DATA WRAPPER clickhouse_fdw OPTIONS(dbname 'binary_inserts_test', driver 'binary'); +CREATE USER MAPPING FOR CURRENT_USER SERVER binary_inserts_loopback; +SELECT clickhouse_raw_query('drop database if exists binary_inserts_test'); + clickhouse_raw_query +---------------------- + +(1 row) + +SELECT clickhouse_raw_query('create database binary_inserts_test'); + clickhouse_raw_query +---------------------- + +(1 row) + +SELECT clickhouse_raw_query('CREATE TABLE binary_inserts_test.ints ( + c1 Int8, c2 Int16, c3 Int32, c4 Int64 +) ENGINE = MergeTree PARTITION BY c1 ORDER BY (c1); +'); + clickhouse_raw_query +---------------------- + +(1 row) + +SELECT clickhouse_raw_query('CREATE TABLE binary_inserts_test.uints ( + c1 UInt8, c2 UInt16, c3 UInt32, c4 UInt64 +) ENGINE = MergeTree PARTITION BY c1 ORDER BY (c1); +'); + clickhouse_raw_query +---------------------- + +(1 row) + +SELECT clickhouse_raw_query('CREATE TABLE binary_inserts_test.floats ( + c1 Float32, c2 Float64 +) ENGINE = MergeTree PARTITION BY c1 ORDER BY (c1) SETTINGS allow_floating_point_partition_key=1; +'); + clickhouse_raw_query +---------------------- + +(1 row) + +SELECT clickhouse_raw_query('CREATE TABLE binary_inserts_test.null_ints ( + c1 Int8, c2 Nullable(Int32) +) ENGINE = MergeTree PARTITION BY c1 ORDER BY (c1); +'); + clickhouse_raw_query +---------------------- + +(1 row) + +SELECT clickhouse_raw_query('CREATE TABLE binary_inserts_test.complex ( + c1 Int32, c2 Date, c3 DateTime, c4 String, c5 FixedString(10), c6 LowCardinality(String), c7 DateTime64(3) +) ENGINE = MergeTree PARTITION BY c1 ORDER BY (c1); +'); + clickhouse_raw_query +---------------------- + +(1 row) + +SELECT clickhouse_raw_query('CREATE TABLE binary_inserts_test.arrays ( + c1 Int32, c2 Array(Int32) +) ENGINE = MergeTree PARTITION BY c1 ORDER BY (c1); +'); + clickhouse_raw_query +---------------------- + +(1 row) + +IMPORT FOREIGN SCHEMA "binary_inserts_test" FROM SERVER binary_inserts_loopback INTO public; +NOTICE: pg_clickhouse: ClickHouse type was translated to type for column "c1", change it to BOOLEAN if needed +/* ints */ +INSERT INTO ints + SELECT i, i + 1, i + 2, i+ 3 FROM generate_series(1, 3) i; +SELECT * FROM ints ORDER BY c1; + c1 | c2 | c3 | c4 +----+----+----+---- + 1 | 2 | 3 | 4 + 2 | 3 | 4 | 5 + 3 | 4 | 5 | 6 +(3 rows) + +INSERT INTO ints (c1, c4, c3, c2) + SELECT i, i + 1, i + 2, i+ 3 FROM generate_series(4, 6) i; +SELECT * FROM ints ORDER BY c1; + c1 | c2 | c3 | c4 +----+----+----+---- + 1 | 2 | 3 | 4 + 2 | 3 | 4 | 5 + 3 | 4 | 5 | 6 + 4 | 7 | 6 | 5 + 5 | 8 | 7 | 6 + 6 | 9 | 8 | 7 +(6 rows) + +/* check dropping columns (that will change attnums) */ +ALTER TABLE ints DROP COLUMN c1; +ALTER TABLE ints ADD COLUMN c1 SMALLINT; +INSERT INTO ints (c1, c2, c3, c4) + SELECT i, i + 1, i + 2, i+ 3 FROM generate_series(7, 8) i; +SELECT c1, c2, c3, c4 FROM ints ORDER BY c1; + c1 | c2 | c3 | c4 +----+----+----+---- + 1 | 2 | 3 | 4 + 2 | 3 | 4 | 5 + 3 | 4 | 5 | 6 + 4 | 7 | 6 | 5 + 5 | 8 | 7 | 6 + 6 | 9 | 8 | 7 + 7 | 8 | 9 | 10 + 8 | 9 | 10 | 11 +(8 rows) + +/* check other number types */ +INSERT INTO uints + SELECT i, i + 1, i + 2, i+ 3 FROM generate_series(1, 3) i; +SELECT * FROM uints ORDER BY c1; + c1 | c2 | c3 | c4 +----+----+----+---- + 1 | 2 | 3 | 4 + 2 | 3 | 4 | 5 + 3 | 4 | 5 | 6 +(3 rows) + +INSERT INTO floats + SELECT i * 1.1, i + 2.1 FROM generate_series(1, 3) i; +SELECT * FROM floats ORDER BY c1; + c1 | c2 +-----+----- + 1.1 | 3.1 + 2.2 | 4.1 + 3.3 | 5.1 +(3 rows) + +/* check nullable */ +INSERT INTO null_ints SELECT i, case WHEN i % 2 = 0 THEN NULL ELSE i END FROM generate_series(1, 10) i; +INSERT INTO null_ints(c1) SELECT i FROM generate_series(11, 13) i; +SELECT * FROM null_ints ORDER BY c1; + c1 | c2 +----+---- + 1 | 1 + 2 | + 3 | 3 + 4 | + 5 | 5 + 6 | + 7 | 7 + 8 | + 9 | 9 + 10 | + 11 | + 12 | + 13 | +(13 rows) + +SELECT * FROM null_ints ORDER BY c1; + c1 | c2 +----+---- + 1 | 1 + 2 | + 3 | 3 + 4 | + 5 | 5 + 6 | + 7 | 7 + 8 | + 9 | 9 + 10 | + 11 | + 12 | + 13 | +(13 rows) + +/* check dates and strings */ +ALTER TABLE complex ALTER COLUMN c7 SET DATA TYPE timestamp(3); +\d+ complex + Foreign table "public.complex" + Column | Type | Collation | Nullable | Default | FDW options | Storage | Stats target | Description +--------+--------------------------------+-----------+----------+---------+-------------+----------+--------------+------------- + c1 | integer | | not null | | | plain | | + c2 | date | | not null | | | plain | | + c3 | timestamp without time zone | | not null | | | plain | | + c4 | text | | not null | | | extended | | + c5 | character varying(10) | | not null | | | extended | | + c6 | text | | not null | | | extended | | + c7 | timestamp(3) without time zone | | not null | | | plain | | +Server: binary_inserts_loopback +FDW options: (database 'binary_inserts_test', table_name 'complex', engine 'MergeTree') + +INSERT INTO complex VALUES + (1, '2020-06-01', '2020-06-02 10:01:02', 't1', 'fix_t1', 'low1', '2020-06-02 10:01:02.123'), + (2, '2020-06-02', '2020-06-03 10:01:02', 5, 'fix_t2', 'low2', '2020-06-03 11:01:02.234'), + (3, '2020-06-03', '2020-06-04 10:01:02', 5, 'fix_t3', 'low3', '2020-06-04 12:01:02'); +SELECT * FROM complex ORDER BY c1; + c1 | c2 | c3 | c4 | c5 | c6 | c7 +----+------------+---------------------+----+--------+------+---------------------------- + 1 | 2020-06-01 | 2020-06-02 10:01:02 | t1 | fix_t1 | low1 | 2020-06-02 10:01:02.122999 + 2 | 2020-06-02 | 2020-06-03 10:01:02 | 5 | fix_t2 | low2 | 2020-06-03 11:01:02.234 + 3 | 2020-06-03 | 2020-06-04 10:01:02 | 5 | fix_t3 | low3 | 2020-06-04 12:01:02 +(3 rows) + +/* check arrays */ +INSERT INTO arrays VALUES + (1, ARRAY[1,2]), + (2, ARRAY[3,4,5]), + (3, ARRAY[6,4]); +SELECT * FROM arrays ORDER BY c1; + c1 | c2 +----+--------- + 1 | {1,2} + 2 | {3,4,5} + 3 | {6,4} +(3 rows) + +DROP USER MAPPING FOR CURRENT_USER SERVER binary_inserts_loopback; +SELECT clickhouse_raw_query('DROP DATABASE binary_inserts_test'); + clickhouse_raw_query +---------------------- + +(1 row) + +DROP SERVER binary_inserts_loopback CASCADE; +NOTICE: drop cascades to 6 other objects +DETAIL: drop cascades to foreign table arrays +drop cascades to foreign table complex +drop cascades to foreign table floats +drop cascades to foreign table ints +drop cascades to foreign table null_ints +drop cascades to foreign table uints diff --git a/test/expected/result_map.txt b/test/expected/result_map.txt index f94916d2..16736c37 100644 --- a/test/expected/result_map.txt +++ b/test/expected/result_map.txt @@ -7,6 +7,18 @@ ClickHouse they cover. * Postgres coverage run using latest ClickHouse release. * ClickHouse coverage run from PostgreSQL 18. +binary_inserts.sql +------------------ + + Postgres | File +----------|---------------------- + 18 | binary_inserts.out + 13-17 | binary_inserts_1.out + + ClickHouse | File +------------|-------------------- + 22-25 | binary_inserts.out + binary_queries.sql ------------------ @@ -33,7 +45,7 @@ deparse_checks.sql 13-17 | deparse_checks_1.out ClickHouse | File -------------|---------------------- +------------|-------------------- 22-25 | deparse_checks.out engines.sql diff --git a/test/sql/binary_inserts.sql b/test/sql/binary_inserts.sql new file mode 100644 index 00000000..eb5d6d02 --- /dev/null +++ b/test/sql/binary_inserts.sql @@ -0,0 +1,86 @@ +SET datestyle = 'ISO'; +CREATE SERVER binary_inserts_loopback FOREIGN DATA WRAPPER clickhouse_fdw OPTIONS(dbname 'binary_inserts_test', driver 'binary'); +CREATE USER MAPPING FOR CURRENT_USER SERVER binary_inserts_loopback; + +SELECT clickhouse_raw_query('drop database if exists binary_inserts_test'); +SELECT clickhouse_raw_query('create database binary_inserts_test'); +SELECT clickhouse_raw_query('CREATE TABLE binary_inserts_test.ints ( + c1 Int8, c2 Int16, c3 Int32, c4 Int64 +) ENGINE = MergeTree PARTITION BY c1 ORDER BY (c1); +'); + +SELECT clickhouse_raw_query('CREATE TABLE binary_inserts_test.uints ( + c1 UInt8, c2 UInt16, c3 UInt32, c4 UInt64 +) ENGINE = MergeTree PARTITION BY c1 ORDER BY (c1); +'); + +SELECT clickhouse_raw_query('CREATE TABLE binary_inserts_test.floats ( + c1 Float32, c2 Float64 +) ENGINE = MergeTree PARTITION BY c1 ORDER BY (c1) SETTINGS allow_floating_point_partition_key=1; +'); + +SELECT clickhouse_raw_query('CREATE TABLE binary_inserts_test.null_ints ( + c1 Int8, c2 Nullable(Int32) +) ENGINE = MergeTree PARTITION BY c1 ORDER BY (c1); +'); + +SELECT clickhouse_raw_query('CREATE TABLE binary_inserts_test.complex ( + c1 Int32, c2 Date, c3 DateTime, c4 String, c5 FixedString(10), c6 LowCardinality(String), c7 DateTime64(3) +) ENGINE = MergeTree PARTITION BY c1 ORDER BY (c1); +'); + +SELECT clickhouse_raw_query('CREATE TABLE binary_inserts_test.arrays ( + c1 Int32, c2 Array(Int32) +) ENGINE = MergeTree PARTITION BY c1 ORDER BY (c1); +'); + +IMPORT FOREIGN SCHEMA "binary_inserts_test" FROM SERVER binary_inserts_loopback INTO public; + +/* ints */ +INSERT INTO ints + SELECT i, i + 1, i + 2, i+ 3 FROM generate_series(1, 3) i; +SELECT * FROM ints ORDER BY c1; +INSERT INTO ints (c1, c4, c3, c2) + SELECT i, i + 1, i + 2, i+ 3 FROM generate_series(4, 6) i; +SELECT * FROM ints ORDER BY c1; + +/* check dropping columns (that will change attnums) */ +ALTER TABLE ints DROP COLUMN c1; +ALTER TABLE ints ADD COLUMN c1 SMALLINT; +INSERT INTO ints (c1, c2, c3, c4) + SELECT i, i + 1, i + 2, i+ 3 FROM generate_series(7, 8) i; +SELECT c1, c2, c3, c4 FROM ints ORDER BY c1; + +/* check other number types */ +INSERT INTO uints + SELECT i, i + 1, i + 2, i+ 3 FROM generate_series(1, 3) i; +SELECT * FROM uints ORDER BY c1; +INSERT INTO floats + SELECT i * 1.1, i + 2.1 FROM generate_series(1, 3) i; +SELECT * FROM floats ORDER BY c1; + +/* check nullable */ +INSERT INTO null_ints SELECT i, case WHEN i % 2 = 0 THEN NULL ELSE i END FROM generate_series(1, 10) i; +INSERT INTO null_ints(c1) SELECT i FROM generate_series(11, 13) i; +SELECT * FROM null_ints ORDER BY c1; +SELECT * FROM null_ints ORDER BY c1; + +/* check dates and strings */ +ALTER TABLE complex ALTER COLUMN c7 SET DATA TYPE timestamp(3); +\d+ complex +INSERT INTO complex VALUES + (1, '2020-06-01', '2020-06-02 10:01:02', 't1', 'fix_t1', 'low1', '2020-06-02 10:01:02.123'), + (2, '2020-06-02', '2020-06-03 10:01:02', 5, 'fix_t2', 'low2', '2020-06-03 11:01:02.234'), + (3, '2020-06-03', '2020-06-04 10:01:02', 5, 'fix_t3', 'low3', '2020-06-04 12:01:02'); +SELECT * FROM complex ORDER BY c1; + +/* check arrays */ +INSERT INTO arrays VALUES + (1, ARRAY[1,2]), + (2, ARRAY[3,4,5]), + (3, ARRAY[6,4]); +SELECT * FROM arrays ORDER BY c1; + +DROP USER MAPPING FOR CURRENT_USER SERVER binary_inserts_loopback; +SELECT clickhouse_raw_query('DROP DATABASE binary_inserts_test'); +DROP SERVER binary_inserts_loopback CASCADE; diff --git a/vendor/clickhouse-cpp b/vendor/clickhouse-cpp index 69195246..b8544bbf 160000 --- a/vendor/clickhouse-cpp +++ b/vendor/clickhouse-cpp @@ -1 +1 @@ -Subproject commit 69195246a3b39542c397ef27df9f46ec4a4bf206 +Subproject commit b8544bbf43140a0490a8929e7a726de466aefff3