private async ValueTask WriteRow(IReadOnlyCollection <object?> values, bool async, CancellationToken cancellationToken) { if (values == null) { throw new ArgumentNullException(nameof(values)); } if (values.Count != _columns.Count) { throw new ArgumentException("The number of values must be equal to the number of columns."); } var columnWriters = new List <IClickHouseColumnWriter>(_columns.Count); foreach (var value in values) { int i = columnWriters.Count; var columnInfo = _columns[i]; SingleRowColumnWriterDispatcher dispatcher; Type valueType; if (value != null && !(value is DBNull)) { dispatcher = new SingleRowColumnWriterDispatcher(value, columnInfo, _columnSettings?[i]); valueType = value.GetType(); } else if (columnInfo.TypeInfo.TypeName != "Nullable") { throw new ClickHouseException(ClickHouseErrorCodes.ColumnMismatch, $"The column \"{columnInfo.Name}\" at the position {i} doesn't support nulls."); } else { dispatcher = new SingleRowColumnWriterDispatcher(null, columnInfo, _columnSettings?[i]); valueType = columnInfo.TypeInfo.GetFieldType(); } IClickHouseColumnWriter columnWriter; try { columnWriter = TypeDispatcher.Dispatch(valueType, dispatcher); } catch (ClickHouseException ex) { throw new ClickHouseException(ex.ErrorCode, $"Column \"{columnInfo.Name}\" (position {i}): {ex.Message}", ex); } columnWriters.Add(columnWriter); } var table = new ClickHouseTableWriter(string.Empty, 1, columnWriters); await SendTable(table, async, cancellationToken); }
private async ValueTask SendTable(ClickHouseTableWriter table, bool async, CancellationToken cancellationToken) { try { await _session.SendTable(table, async, cancellationToken); } catch (ClickHouseHandledException) { throw; } catch (Exception ex) { var aggrEx = await _session.SetFailed(ex, false, async); if (aggrEx != null) { throw aggrEx; } throw; } }
private async ValueTask WriteTable(IReadOnlyList <object?> columns, int rowCount, bool async, CancellationToken cancellationToken) { if (columns == null) { throw new ArgumentNullException(nameof(columns)); } if (columns.Count != _columns.Count) { throw new ArgumentException("The number of columns for writing must be equal to the number of columns in the table.", nameof(columns)); } if (rowCount < 0) { throw new ArgumentOutOfRangeException(nameof(rowCount)); } if (rowCount == 0) { throw new ArgumentException("The number of rows must be grater than zero.", nameof(rowCount)); } if (IsClosed) { throw new ClickHouseException(ClickHouseErrorCodes.InvalidConnectionState, "The writer is closed."); } var writers = new List <IClickHouseColumnWriter>(_columns.Count); for (int i = 0; i < _columns.Count; i++) { var column = columns[i]; var columnInfo = _columns[i]; if (column == null) { if (!columnInfo.TypeInfo.TypeName.StartsWith("Nullable")) { throw new ClickHouseException(ClickHouseErrorCodes.ColumnMismatch, $"The column \"{columnInfo.Name}\" at the position {i} doesn't support nulls."); } var constColumn = TypeDispatcher.Dispatch(columnInfo.TypeInfo.GetFieldType(), new NullColumnWriterDispatcher(columnInfo, _columnSettings?[i], rowCount)); writers.Add(constColumn); continue; } var columnType = column.GetType(); bool isEnumerable = false; Type?enumerable = null, asyncEnumerable = null, readOnlyList = null, list = null; foreach (var ifs in columnType.GetInterfaces()) { if (ifs == typeof(IEnumerable)) { isEnumerable = true; } else if (ifs.IsGenericType) { var ifsDefinition = ifs.GetGenericTypeDefinition(); if (ifsDefinition == typeof(IEnumerable <>)) { enumerable ??= ifs; } else if (ifsDefinition == typeof(IAsyncEnumerable <>)) { asyncEnumerable ??= ifs; } else if (ifsDefinition == typeof(IReadOnlyList <>)) { readOnlyList ??= ifs; } else if (ifsDefinition == typeof(IList <>)) { list ??= ifs; } } } Type dispatchedElementType; if (readOnlyList != null) { dispatchedElementType = readOnlyList.GetGenericArguments()[0]; } else if (list != null) { dispatchedElementType = list.GetGenericArguments()[0]; } else { if (asyncEnumerable != null) { if (async) { var genericArg = asyncEnumerable.GetGenericArguments()[0]; var asyncDispatcher = new AsyncColumnWriterDispatcher(column, columnInfo, _columnSettings?[i], rowCount, i, cancellationToken); var asyncColumn = await TypeDispatcher.Dispatch(genericArg, asyncDispatcher); writers.Add(asyncColumn); continue; } if (!isEnumerable && enumerable == null) { throw new ClickHouseException( ClickHouseErrorCodes.ColumnMismatch, $"The column \"{columnInfo.Name}\" at the position {i} implements interface \"{asyncEnumerable}\". Call async method \"{nameof(WriteTableAsync)}\"."); } } if (enumerable != null) { dispatchedElementType = enumerable.GetGenericArguments()[0]; } else if (isEnumerable) { dispatchedElementType = columnInfo.TypeInfo.GetFieldType(); } else { throw new ClickHouseException(ClickHouseErrorCodes.ColumnMismatch, $"The column \"{columnInfo.Name}\" at the position {i} is not a collection."); } } var dispatcher = new ColumnWriterDispatcher(column, columnInfo, _columnSettings?[i], rowCount, i); var columnWriter = TypeDispatcher.Dispatch(dispatchedElementType, dispatcher); writers.Add(columnWriter); } var table = new ClickHouseTableWriter(string.Empty, rowCount, writers); await SendTable(table, async, cancellationToken); }