From 5779b37c024d809510a6a011c21b25893eb7c20f Mon Sep 17 00:00:00 2001 From: Dale Mcdiarmid Date: Wed, 19 Oct 2022 15:08:37 +0100 Subject: [PATCH 1/4] enforce sort order of insert for native --- conn_batch.go | 14 +++++ lib/proto/block.go | 44 ++++++++++++++++ tests/issues/741_test.go | 109 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+) create mode 100644 tests/issues/741_test.go diff --git a/conn_batch.go b/conn_batch.go index bd746949d5..556ac4dabe 100644 --- a/conn_batch.go +++ b/conn_batch.go @@ -31,9 +31,18 @@ import ( ) var splitInsertRe = regexp.MustCompile(`(?i)\sVALUES\s*\(`) +var columnMatch = regexp.MustCompile(`.*\((?P.*)\)$`) func (c *connect) prepareBatch(ctx context.Context, query string, release func(*connect, error)) (driver.Batch, error) { query = splitInsertRe.Split(query, -1)[0] + colMatch := columnMatch.FindStringSubmatch(query) + var columns []string + if len(colMatch) == 2 { + columns = strings.Split(colMatch[1], ",") + for i := range columns { + columns[i] = strings.TrimSpace(columns[i]) + } + } if !strings.HasSuffix(strings.TrimSpace(strings.ToUpper(query)), "VALUES") { query += " VALUES" } @@ -54,6 +63,10 @@ func (c *connect) prepareBatch(ctx context.Context, query string, release func(* release(c, err) return nil, err } + // resort batch to specified columns + if err = block.SortColumns(columns); err != nil { + return nil, err + } return &batch{ ctx: ctx, conn: c, @@ -90,6 +103,7 @@ func (b *batch) Append(v ...interface{}) error { if b.sent { return ErrBatchAlreadySent } + // if err := b.block.Append(v...); err != nil { b.release(err) return err diff --git a/lib/proto/block.go b/lib/proto/block.go index 3d93247244..a94bcec816 100644 --- a/lib/proto/block.go +++ b/lib/proto/block.go @@ -20,6 +20,7 @@ package proto import ( "errors" "fmt" + "sort" "time" "github.com/ClickHouse/ch-go/proto" @@ -73,6 +74,49 @@ func (b *Block) ColumnsNames() []string { return b.names } +// SortColumns sorts our block according to the requested order - a slice of column names. Names must be identical in requested order and block. +func (b *Block) SortColumns(columns []string) error { + if len(columns) == 0 { + // no preferred sort order + return nil + } + if len(columns) != len(b.Columns) { + return fmt.Errorf("requested column order is incorrect length to sort block - expected %d, got %d", len(b.Columns), len(columns)) + } + missing := difference(b.names, columns) + if len(missing) > 0 { + return fmt.Errorf("block cannot be sorted - missing columns in requested order: %v", missing) + } + lookup := make(map[string]int) + for i, col := range columns { + lookup[col] = i + } + // we assume both lists have the same + sort.Slice(b.Columns, func(i, j int) bool { + iRank, jRank := lookup[b.Columns[i].Name()], lookup[b.Columns[j].Name()] + return iRank < jRank + }) + sort.Slice(b.names, func(i, j int) bool { + iRank, jRank := lookup[b.names[i]], lookup[b.names[j]] + return iRank < jRank + }) + return nil +} + +func difference(a, b []string) []string { + mb := make(map[string]struct{}, len(b)) + for _, x := range b { + mb[x] = struct{}{} + } + var diff []string + for _, x := range a { + if _, found := mb[x]; !found { + diff = append(diff, x) + } + } + return diff +} + func (b *Block) Encode(buffer *proto.Buffer, revision uint64) error { if revision > 0 { encodeBlockInfo(buffer) diff --git a/tests/issues/741_test.go b/tests/issues/741_test.go new file mode 100644 index 0000000000..c5b05bf395 --- /dev/null +++ b/tests/issues/741_test.go @@ -0,0 +1,109 @@ +package issues + +import ( + "fmt" + "github.com/ClickHouse/clickhouse-go/v2" + clickhouse_tests "github.com/ClickHouse/clickhouse-go/v2/tests" + clickhouse_std_tests "github.com/ClickHouse/clickhouse-go/v2/tests/std" + "github.com/stretchr/testify/require" + "math/rand" + "strconv" + "strings" + "testing" +) + +func TestIssue741(t *testing.T) { + useSSL, err := strconv.ParseBool(clickhouse_tests.GetEnv("CLICKHOUSE_USE_SSL", "false")) + require.NoError(t, err) + conn, err := clickhouse_std_tests.GetDSNConnection("issues", clickhouse.Native, useSSL, "false") + require.NoError(t, err) + conn.Exec("DROP TABLE IF EXISTS issue_741") + ddl := ` + CREATE TABLE issue_741 ( + Col1 String, + Col2 Int64 + ) + Engine MergeTree() ORDER BY tuple() + ` + _, err = conn.Exec(ddl) + require.NoError(t, err) + defer func() { + conn.Exec("DROP TABLE issue_741") + }() + stmt, err := conn.Prepare("INSERT INTO issue_741 (Col2, Col1) VALUES (? ?)") + _, err = stmt.Exec(int64(1), "1") + require.NoError(t, err) +} + +func TestIssue741SingleColumn(t *testing.T) { + useSSL, err := strconv.ParseBool(clickhouse_tests.GetEnv("CLICKHOUSE_USE_SSL", "false")) + require.NoError(t, err) + conn, err := clickhouse_std_tests.GetDSNConnection("issues", clickhouse.Native, useSSL, "false") + require.NoError(t, err) + conn.Exec("DROP TABLE IF EXISTS issue_741_single") + ddl := ` + CREATE TABLE issue_741_single ( + Col1 String, + Col2 Int64 + ) + Engine MergeTree() ORDER BY tuple() + ` + _, err = conn.Exec(ddl) + require.NoError(t, err) + defer func() { + conn.Exec("DROP TABLE issue_741_single") + }() + stmt, err := conn.Prepare("INSERT INTO issue_741_single (Col1) VALUES (?)") + _, err = stmt.Exec("1") + require.NoError(t, err) +} + +func TestIssue741RandomOrder(t *testing.T) { + columns := map[string]interface{}{ + "Col1 String": "a", + "Col2 Int64": int64(1), + "Col3 Int32": int32(2), + "Col4 Bool": true, + } + useSSL, err := strconv.ParseBool(clickhouse_tests.GetEnv("CLICKHOUSE_USE_SSL", "false")) + require.NoError(t, err) + conn, err := clickhouse_std_tests.GetDSNConnection("issues", clickhouse.Native, useSSL, "false") + require.NoError(t, err) + conn.Exec("DROP TABLE IF EXISTS issue_741_random") + colNames := make([]string, len(columns)) + i := 0 + for k := range columns { + colNames[i] = k + i++ + } + // shuffle our columns for ddl + rand.Shuffle(len(colNames), func(i, j int) { colNames[i], colNames[j] = colNames[j], colNames[i] }) + ddl := fmt.Sprintf(` + CREATE TABLE issue_741_random ( + %s + ) + Engine MergeTree() ORDER BY tuple()`, strings.Join(colNames, ", ")) + _, err = conn.Exec(ddl) + require.NoError(t, err) + defer func() { + conn.Exec("DROP TABLE issue_741_random") + }() + // shuffle our columns for insert + rand.Shuffle(len(colNames), func(i, j int) { colNames[i], colNames[j] = colNames[j], colNames[i] }) + names := make([]string, len(colNames)) + placeholders := make([]string, len(colNames)) + for i := range colNames { + names[i] = strings.Fields(colNames[i])[0] + placeholders[i] = "?" + } + stmt, err := conn.Prepare(fmt.Sprintf("INSERT INTO issue_741_random (%s) VALUES (%s)", strings.Join(names, ", "), strings.Join(placeholders, ", "))) + require.NoError(t, err) + values := make([]interface{}, len(colNames)) + for i, colName := range colNames { + values[i] = columns[colName] + } + _, err = stmt.Exec(values...) + require.NoError(t, err) +} + +// test Append From 957f236daf23d80aaf52d80e6cd6ef14cad28b77 Mon Sep 17 00:00:00 2001 From: Dale Mcdiarmid Date: Wed, 19 Oct 2022 15:38:55 +0100 Subject: [PATCH 2/4] test append behaviour --- tests/issues/741_test.go | 57 +++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/tests/issues/741_test.go b/tests/issues/741_test.go index c5b05bf395..a18a56feb3 100644 --- a/tests/issues/741_test.go +++ b/tests/issues/741_test.go @@ -1,6 +1,7 @@ package issues import ( + "context" "fmt" "github.com/ClickHouse/clickhouse-go/v2" clickhouse_tests "github.com/ClickHouse/clickhouse-go/v2/tests" @@ -58,18 +59,13 @@ func TestIssue741SingleColumn(t *testing.T) { require.NoError(t, err) } -func TestIssue741RandomOrder(t *testing.T) { +func generateRandomInsert(tableName string) (string, string, []interface{}) { columns := map[string]interface{}{ "Col1 String": "a", "Col2 Int64": int64(1), "Col3 Int32": int32(2), "Col4 Bool": true, } - useSSL, err := strconv.ParseBool(clickhouse_tests.GetEnv("CLICKHOUSE_USE_SSL", "false")) - require.NoError(t, err) - conn, err := clickhouse_std_tests.GetDSNConnection("issues", clickhouse.Native, useSSL, "false") - require.NoError(t, err) - conn.Exec("DROP TABLE IF EXISTS issue_741_random") colNames := make([]string, len(columns)) i := 0 for k := range columns { @@ -79,15 +75,10 @@ func TestIssue741RandomOrder(t *testing.T) { // shuffle our columns for ddl rand.Shuffle(len(colNames), func(i, j int) { colNames[i], colNames[j] = colNames[j], colNames[i] }) ddl := fmt.Sprintf(` - CREATE TABLE issue_741_random ( + CREATE TABLE %s ( %s ) - Engine MergeTree() ORDER BY tuple()`, strings.Join(colNames, ", ")) - _, err = conn.Exec(ddl) - require.NoError(t, err) - defer func() { - conn.Exec("DROP TABLE issue_741_random") - }() + Engine MergeTree() ORDER BY tuple()`, tableName, strings.Join(colNames, ", ")) // shuffle our columns for insert rand.Shuffle(len(colNames), func(i, j int) { colNames[i], colNames[j] = colNames[j], colNames[i] }) names := make([]string, len(colNames)) @@ -96,14 +87,48 @@ func TestIssue741RandomOrder(t *testing.T) { names[i] = strings.Fields(colNames[i])[0] placeholders[i] = "?" } - stmt, err := conn.Prepare(fmt.Sprintf("INSERT INTO issue_741_random (%s) VALUES (%s)", strings.Join(names, ", "), strings.Join(placeholders, ", "))) - require.NoError(t, err) + insertStatement := fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)", tableName, strings.Join(names, ", "), strings.Join(placeholders, ", ")) values := make([]interface{}, len(colNames)) for i, colName := range colNames { values[i] = columns[colName] } + return ddl, insertStatement, values +} + +func TestIssue741RandomOrder(t *testing.T) { + useSSL, err := strconv.ParseBool(clickhouse_tests.GetEnv("CLICKHOUSE_USE_SSL", "false")) + require.NoError(t, err) + conn, err := clickhouse_std_tests.GetDSNConnection("issues", clickhouse.Native, useSSL, "false") + require.NoError(t, err) + conn.Exec("DROP TABLE IF EXISTS issue_741_random") + defer func() { + conn.Exec("DROP TABLE issue_741_random") + }() + ddl, insertStatement, values := generateRandomInsert("issue_741_random") + _, err = conn.Exec(ddl) + require.NoError(t, err) + stmt, err := conn.Prepare(fmt.Sprintf(insertStatement)) + require.NoError(t, err) _, err = stmt.Exec(values...) require.NoError(t, err) } -// test Append +// test Append on native connection +func TestIssue741Append(t *testing.T) { + var ( + conn, err = clickhouse_tests.GetConnection("issues", clickhouse.Settings{ + "max_execution_time": 60, + }, nil, &clickhouse.Compression{ + Method: clickhouse.CompressionLZ4, + }) + ) + ctx := context.Background() + require.NoError(t, err) + conn.Exec(ctx, "DROP TABLE IF EXISTS issue_741_append_random") + ddl, insertStatement, values := generateRandomInsert("issue_741_append_random") + require.NoError(t, conn.Exec(ctx, ddl)) + batch, err := conn.PrepareBatch(ctx, insertStatement) + require.NoError(t, err) + require.NoError(t, batch.Append(values...)) + require.NoError(t, batch.Send()) +} From 08567c6d708c78daa96cb10fd83b87898bd3b13c Mon Sep 17 00:00:00 2001 From: Dale Mcdiarmid Date: Wed, 19 Oct 2022 17:42:41 +0100 Subject: [PATCH 3/4] http support for out of order columns --- conn_batch.go | 2 +- conn_http_batch.go | 48 +++++++++++++++++++++++------- tests/issues/741_test.go | 52 ++++++++++++++++++++------------- tests/std/connect_check_test.go | 2 +- 4 files changed, 70 insertions(+), 34 deletions(-) diff --git a/conn_batch.go b/conn_batch.go index 556ac4dabe..2fed84d150 100644 --- a/conn_batch.go +++ b/conn_batch.go @@ -31,7 +31,7 @@ import ( ) var splitInsertRe = regexp.MustCompile(`(?i)\sVALUES\s*\(`) -var columnMatch = regexp.MustCompile(`.*\((?P.*)\)$`) +var columnMatch = regexp.MustCompile(`.*\((?P.+)\)$`) func (c *connect) prepareBatch(ctx context.Context, query string, release func(*connect, error)) (driver.Batch, error) { query = splitInsertRe.Split(query, -1)[0] diff --git a/conn_http_batch.go b/conn_http_batch.go index 97a9484476..dcc29a26f8 100644 --- a/conn_http_batch.go +++ b/conn_http_batch.go @@ -27,19 +27,27 @@ import ( "io" "io/ioutil" "regexp" + "strings" ) -var splitHttpInsertRe = regexp.MustCompile("(?i)^INSERT INTO\\s+`?([\\w.]+)`?") +// \x60 represents a backtick +var httpInsertRe = regexp.MustCompile(`(?i)^INSERT INTO\s+\x60?([\w.^\(]+)\x60?\s*(\([^\)]*\))?`) // release is ignored, because http used by std with empty release function func (h *httpConnect) prepareBatch(ctx context.Context, query string, release func(*connect, error)) (driver.Batch, error) { - index := splitHttpInsertRe.FindStringSubmatchIndex(query) - - if len(index) < 3 { + matches := httpInsertRe.FindStringSubmatch(query) + if len(matches) < 3 { return nil, errors.New("cannot get table name from query") } - - tableName := query[index[2]:index[3]] + tableName := matches[1] + var rColumns []string + if matches[2] != "" { + colMatch := strings.TrimSuffix(strings.TrimPrefix(matches[2], "("), ")") + rColumns = strings.Split(colMatch, ",") + for i := range rColumns { + rColumns[i] = strings.TrimSpace(rColumns[i]) + } + } query = "INSERT INTO " + tableName + " FORMAT Native" queryTableSchema := "DESCRIBE TABLE " + tableName r, err := h.query(ctx, release, queryTableSchema) @@ -50,6 +58,8 @@ func (h *httpConnect) prepareBatch(ctx context.Context, query string, release fu block := &proto.Block{} // get Table columns and types + columns := make(map[string]string) + var colNames []string for r.Next() { var ( colName string @@ -57,14 +67,30 @@ func (h *httpConnect) prepareBatch(ctx context.Context, query string, release fu ignore string ) - err = r.Scan(&colName, &colType, &ignore, &ignore, &ignore, &ignore, &ignore) - if err != nil { + if err = r.Scan(&colName, &colType, &ignore, &ignore, &ignore, &ignore, &ignore); err != nil { return nil, err } + colNames = append(colNames, colName) + columns[colName] = colType + } - err = block.AddColumn(colName, column.Type(colType)) - if err != nil { - return nil, err + switch len(rColumns) { + case 0: + for _, colName := range colNames { + if err = block.AddColumn(colName, column.Type(columns[colName])); err != nil { + return nil, err + } + } + default: + // user has requested specific columns so only include these + for _, colName := range rColumns { + if colType, ok := columns[colName]; ok { + if err = block.AddColumn(colName, column.Type(colType)); err != nil { + return nil, err + } + } else { + return nil, fmt.Errorf("column %s is not present in the table %s", colName, tableName) + } } } diff --git a/tests/issues/741_test.go b/tests/issues/741_test.go index a18a56feb3..7999e7223b 100644 --- a/tests/issues/741_test.go +++ b/tests/issues/741_test.go @@ -14,26 +14,31 @@ import ( ) func TestIssue741(t *testing.T) { - useSSL, err := strconv.ParseBool(clickhouse_tests.GetEnv("CLICKHOUSE_USE_SSL", "false")) - require.NoError(t, err) - conn, err := clickhouse_std_tests.GetDSNConnection("issues", clickhouse.Native, useSSL, "false") - require.NoError(t, err) - conn.Exec("DROP TABLE IF EXISTS issue_741") - ddl := ` - CREATE TABLE issue_741 ( - Col1 String, - Col2 Int64 - ) - Engine MergeTree() ORDER BY tuple() - ` - _, err = conn.Exec(ddl) - require.NoError(t, err) - defer func() { - conn.Exec("DROP TABLE issue_741") - }() - stmt, err := conn.Prepare("INSERT INTO issue_741 (Col2, Col1) VALUES (? ?)") - _, err = stmt.Exec(int64(1), "1") - require.NoError(t, err) + protocols := []clickhouse.Protocol{clickhouse.Native, clickhouse.HTTP} + for _, protocol := range protocols { + t.Run(fmt.Sprintf("%v Protocol", protocol), func(t *testing.T) { + useSSL, err := strconv.ParseBool(clickhouse_tests.GetEnv("CLICKHOUSE_USE_SSL", "false")) + require.NoError(t, err) + conn, err := clickhouse_std_tests.GetDSNConnection("issues", protocol, useSSL, "false") + require.NoError(t, err) + conn.Exec("DROP TABLE IF EXISTS issue_741") + ddl := ` + CREATE TABLE issue_741 ( + Col1 String, + Col2 Int64 + ) + Engine MergeTree() ORDER BY tuple() + ` + _, err = conn.Exec(ddl) + require.NoError(t, err) + defer func() { + conn.Exec("DROP TABLE issue_741") + }() + stmt, err := conn.Prepare("INSERT INTO issue_741 (Col2, Col1) VALUES (? ?)") + _, err = stmt.Exec(int64(1), "1") + require.NoError(t, err) + }) + } } func TestIssue741SingleColumn(t *testing.T) { @@ -114,7 +119,7 @@ func TestIssue741RandomOrder(t *testing.T) { } // test Append on native connection -func TestIssue741Append(t *testing.T) { +func TestIssue741NativeAppend(t *testing.T) { var ( conn, err = clickhouse_tests.GetConnection("issues", clickhouse.Settings{ "max_execution_time": 60, @@ -132,3 +137,8 @@ func TestIssue741Append(t *testing.T) { require.NoError(t, batch.Append(values...)) require.NoError(t, batch.Send()) } + +// test Append on native connection +func TestIssue741StdAppend(t *testing.T) { + //test http and native +} diff --git a/tests/std/connect_check_test.go b/tests/std/connect_check_test.go index e51b6e5529..d1bd7c4d4d 100644 --- a/tests/std/connect_check_test.go +++ b/tests/std/connect_check_test.go @@ -37,7 +37,7 @@ func TestStdConnCheck(t *testing.T) { Value String ) Engine MergeTree() ORDER BY tuple() ` - dml = `INSERT INTO clickhouse_test_conn_check VALUES ` + dml = "INSERT INTO `clickhouse_test_conn_check` VALUES " ) env, err := GetStdTestEnvironment() From a9f26c8eba73876cf4a9687dcd49bed65f9d92fd Mon Sep 17 00:00:00 2001 From: Dale Mcdiarmid Date: Wed, 19 Oct 2022 17:54:14 +0100 Subject: [PATCH 4/4] std append tests --- tests/issues/741_test.go | 109 +++++++++++++++++++++++++++------------ 1 file changed, 76 insertions(+), 33 deletions(-) diff --git a/tests/issues/741_test.go b/tests/issues/741_test.go index 7999e7223b..7e6c1af2c5 100644 --- a/tests/issues/741_test.go +++ b/tests/issues/741_test.go @@ -6,19 +6,23 @@ import ( "github.com/ClickHouse/clickhouse-go/v2" clickhouse_tests "github.com/ClickHouse/clickhouse-go/v2/tests" clickhouse_std_tests "github.com/ClickHouse/clickhouse-go/v2/tests/std" + "github.com/google/uuid" + "github.com/shopspring/decimal" "github.com/stretchr/testify/require" "math/rand" + "net" "strconv" "strings" "testing" + "time" ) func TestIssue741(t *testing.T) { + useSSL, err := strconv.ParseBool(clickhouse_tests.GetEnv("CLICKHOUSE_USE_SSL", "false")) + require.NoError(t, err) protocols := []clickhouse.Protocol{clickhouse.Native, clickhouse.HTTP} for _, protocol := range protocols { t.Run(fmt.Sprintf("%v Protocol", protocol), func(t *testing.T) { - useSSL, err := strconv.ParseBool(clickhouse_tests.GetEnv("CLICKHOUSE_USE_SSL", "false")) - require.NoError(t, err) conn, err := clickhouse_std_tests.GetDSNConnection("issues", protocol, useSSL, "false") require.NoError(t, err) conn.Exec("DROP TABLE IF EXISTS issue_741") @@ -44,32 +48,41 @@ func TestIssue741(t *testing.T) { func TestIssue741SingleColumn(t *testing.T) { useSSL, err := strconv.ParseBool(clickhouse_tests.GetEnv("CLICKHOUSE_USE_SSL", "false")) require.NoError(t, err) - conn, err := clickhouse_std_tests.GetDSNConnection("issues", clickhouse.Native, useSSL, "false") - require.NoError(t, err) - conn.Exec("DROP TABLE IF EXISTS issue_741_single") - ddl := ` - CREATE TABLE issue_741_single ( + protocols := []clickhouse.Protocol{clickhouse.Native, clickhouse.HTTP} + for _, protocol := range protocols { + t.Run(fmt.Sprintf("%v Protocol", protocol), func(t *testing.T) { + conn, err := clickhouse_std_tests.GetDSNConnection("issues", protocol, useSSL, "false") + require.NoError(t, err) + conn.Exec("DROP TABLE IF EXISTS issue_741_single") + ddl := ` + CREATE TABLE issue_741_single ( Col1 String, Col2 Int64 ) Engine MergeTree() ORDER BY tuple() - ` - _, err = conn.Exec(ddl) - require.NoError(t, err) - defer func() { - conn.Exec("DROP TABLE issue_741_single") - }() - stmt, err := conn.Prepare("INSERT INTO issue_741_single (Col1) VALUES (?)") - _, err = stmt.Exec("1") - require.NoError(t, err) + ` + _, err = conn.Exec(ddl) + require.NoError(t, err) + defer func() { + conn.Exec("DROP TABLE issue_741_single") + }() + stmt, err := conn.Prepare("INSERT INTO issue_741_single (Col1) VALUES (?)") + _, err = stmt.Exec("1") + require.NoError(t, err) + }) + } } func generateRandomInsert(tableName string) (string, string, []interface{}) { columns := map[string]interface{}{ - "Col1 String": "a", - "Col2 Int64": int64(1), - "Col3 Int32": int32(2), - "Col4 Bool": true, + "Col1 String": "a", + "Col2 Int64": int64(1), + "Col3 Int32": int32(2), + "Col4 Bool": true, + "Col5 Date32": time.Now(), + "Col6 IPv4": net.ParseIP("8.8.8.8"), + "Col7 Decimal32(5)": decimal.New(25, 0), + "Col8 UUID": uuid.New(), } colNames := make([]string, len(columns)) i := 0 @@ -103,19 +116,24 @@ func generateRandomInsert(tableName string) (string, string, []interface{}) { func TestIssue741RandomOrder(t *testing.T) { useSSL, err := strconv.ParseBool(clickhouse_tests.GetEnv("CLICKHOUSE_USE_SSL", "false")) require.NoError(t, err) - conn, err := clickhouse_std_tests.GetDSNConnection("issues", clickhouse.Native, useSSL, "false") - require.NoError(t, err) - conn.Exec("DROP TABLE IF EXISTS issue_741_random") - defer func() { - conn.Exec("DROP TABLE issue_741_random") - }() - ddl, insertStatement, values := generateRandomInsert("issue_741_random") - _, err = conn.Exec(ddl) - require.NoError(t, err) - stmt, err := conn.Prepare(fmt.Sprintf(insertStatement)) - require.NoError(t, err) - _, err = stmt.Exec(values...) - require.NoError(t, err) + protocols := []clickhouse.Protocol{clickhouse.Native, clickhouse.HTTP} + for _, protocol := range protocols { + t.Run(fmt.Sprintf("%v Protocol", protocol), func(t *testing.T) { + conn, err := clickhouse_std_tests.GetDSNConnection("issues", clickhouse.Native, useSSL, "false") + require.NoError(t, err) + conn.Exec("DROP TABLE IF EXISTS issue_741_random") + defer func() { + conn.Exec("DROP TABLE issue_741_random") + }() + ddl, insertStatement, values := generateRandomInsert("issue_741_random") + _, err = conn.Exec(ddl) + require.NoError(t, err) + stmt, err := conn.Prepare(fmt.Sprintf(insertStatement)) + require.NoError(t, err) + _, err = stmt.Exec(values...) + require.NoError(t, err) + }) + } } // test Append on native connection @@ -130,6 +148,9 @@ func TestIssue741NativeAppend(t *testing.T) { ctx := context.Background() require.NoError(t, err) conn.Exec(ctx, "DROP TABLE IF EXISTS issue_741_append_random") + defer func() { + conn.Exec(ctx, "DROP TABLE issue_741_append_random") + }() ddl, insertStatement, values := generateRandomInsert("issue_741_append_random") require.NoError(t, conn.Exec(ctx, ddl)) batch, err := conn.PrepareBatch(ctx, insertStatement) @@ -141,4 +162,26 @@ func TestIssue741NativeAppend(t *testing.T) { // test Append on native connection func TestIssue741StdAppend(t *testing.T) { //test http and native + useSSL, err := strconv.ParseBool(clickhouse_tests.GetEnv("CLICKHOUSE_USE_SSL", "false")) + require.NoError(t, err) + protocols := []clickhouse.Protocol{clickhouse.Native, clickhouse.HTTP} + for _, protocol := range protocols { + t.Run(fmt.Sprintf("%v Protocol", protocol), func(t *testing.T) { + conn, err := clickhouse_std_tests.GetDSNConnection("issues", clickhouse.Native, useSSL, "false") + require.NoError(t, err) + conn.Exec("DROP TABLE IF EXISTS issue_741_std_append_random") + defer func() { + conn.Exec("DROP TABLE issue_741_std_append_random") + }() + ddl, insertStatement, values := generateRandomInsert("issue_741_std_append_random") + _, err = conn.Exec(ddl) + require.NoError(t, err) + scope, err := conn.Begin() + require.NoError(t, err) + batch, err := scope.Prepare(insertStatement) + require.NoError(t, err) + _, err = batch.Exec(values...) + require.NoError(t, err) + }) + } }