public void TestBulkInsert_ExplicitDateTimeFormats(DatabaseType type) { DiscoveredDatabase db = GetTestDatabase(type); DiscoveredTable tbl = db.CreateTable("MyDateTestTable", new[] { new DatabaseColumnRequest("MyDate", new DatabaseTypeRequest(typeof(DateTime))) { AllowNulls = false }, }); //There are no rows in the table yet Assert.AreEqual(0, tbl.GetRowCount()); using (var dt = new DataTable()) { dt.Columns.Add("MyDate"); dt.Rows.Add("20011230"); using (IBulkCopy bulk = tbl.BeginBulkInsert()) { bulk.Timeout = 30; bulk.DateTimeDecider.Settings.ExplicitDateFormats = new [] { "yyyyMMdd" }; bulk.Upload(dt); } } var dtDown = tbl.GetDataTable(); Assert.AreEqual(new DateTime(2001, 12, 30), dtDown.Rows[0]["MyDate"]); }
public void TestBulkInsert_Transaction(DatabaseType type) { DiscoveredDatabase db = GetTestDatabase(type); DiscoveredTable tbl = db.CreateTable("MyBulkInsertTest", new[] { new DatabaseColumnRequest("Name", new DatabaseTypeRequest(typeof(string), 10)), new DatabaseColumnRequest("Age", new DatabaseTypeRequest(typeof(int))) }); Assert.AreEqual(0, tbl.GetRowCount()); using (var dt = new DataTable()) { dt.Columns.Add("Name"); dt.Columns.Add("Age"); dt.Rows.Add("Dave", 50); dt.Rows.Add("Jamie", 60); using (var transaction = tbl.Database.Server.BeginNewTransactedConnection()) { using (IBulkCopy bulk = tbl.BeginBulkInsert(transaction.ManagedTransaction)) { bulk.Timeout = 30; bulk.Upload(dt); //inside transaction the count is 2 Assert.AreEqual(2, tbl.GetRowCount(transaction.ManagedTransaction)); dt.Rows.Clear(); dt.Rows.Add("Frank", 100); bulk.Upload(dt); //inside transaction the count is 3 Assert.AreEqual(3, tbl.GetRowCount(transaction.ManagedTransaction)); } transaction.ManagedTransaction.CommitAndCloseConnection(); } } //Transaction was committed final row count should be 3 Assert.AreEqual(3, tbl.GetRowCount()); }
public void TestBulkInsert_SpacedOutNames(DatabaseType type) { DiscoveredDatabase db = GetTestDatabase(type); DiscoveredTable tbl = db.CreateTable("MyBulkInsertTest", new[] { new DatabaseColumnRequest("Na me", new DatabaseTypeRequest(typeof(string), 10)), new DatabaseColumnRequest("A ge", new DatabaseTypeRequest(typeof(int))) }); //There are no rows in the table yet Assert.AreEqual(0, tbl.GetRowCount()); using (var dt = new DataTable()) { dt.Columns.Add("Na me"); dt.Columns.Add("A ge"); dt.Rows.Add("Dave", 50); dt.Rows.Add("Jamie", 60); using (IBulkCopy bulk = tbl.BeginBulkInsert()) { bulk.Timeout = 30; bulk.Upload(dt); Assert.AreEqual(2, tbl.GetRowCount()); dt.Rows.Clear(); dt.Rows.Add("Frank", 100); bulk.Upload(dt); Assert.AreEqual(3, tbl.GetRowCount()); } } tbl.Insert(new Dictionary <string, object>() { { "Na me", "George" }, { "A ge", "300" } }); Assert.AreEqual(4, tbl.GetRowCount()); }
public void TestBulkInsert_BadDecimalFormat_DecimalError(DatabaseType type) { DiscoveredDatabase db = GetTestDatabase(type); DiscoveredTable tbl = db.CreateTable("MyBulkInsertTest", new[] { new DatabaseColumnRequest("Id", new DatabaseTypeRequest(typeof(int))) { IsAutoIncrement = true, IsPrimaryKey = true }, new DatabaseColumnRequest("Name", new DatabaseTypeRequest(typeof(string), 10)), new DatabaseColumnRequest("Score", new DatabaseTypeRequest(typeof(decimal), null, new DecimalSize(2, 1))), new DatabaseColumnRequest("Age", new DatabaseTypeRequest(typeof(int))) }); //There are no rows in the table yet Assert.AreEqual(0, tbl.GetRowCount()); using (var dt = new DataTable()) { dt.Columns.Add("age"); dt.Columns.Add("name"); dt.Columns.Add("score"); dt.Rows.Add(60, "Jamie", 1.2); dt.Rows.Add(30, "Frank", 1.3); dt.Rows.Add(11, "Toad", "."); //bad data dt.Rows.Add(100, "King"); dt.Rows.Add(10, "Frog"); using (IBulkCopy bulk = tbl.BeginBulkInsert()) { bulk.Timeout = 30; Exception ex = null; try { bulk.Upload(dt); } catch (Exception e) { ex = e; } Assert.IsNotNull(ex, "Expected upload to fail because value on row 2 is bad"); Assert.AreEqual("Failed to parse value '.' in column 'score'", ex.Message); Assert.IsNotNull(ex.InnerException, "Expected parse error to be an inner exception"); StringAssert.Contains("Could not parse string value '.' with Decider Type:DecimalTypeDecider", ex.InnerException.Message); } } }
public virtual void SubmitChunk(DataTable chunk, IDataLoadEventListener job) { _timer.Start(); if (_copy == null) { _copy = InitializeBulkCopy(chunk, job); AssessMissingAndIgnoredColumns(chunk, job); } _copy.Upload(chunk); _timer.Stop(); RaiseEvents(chunk, job); }
public void TestBulkInsert_ColumnOrdinals(DatabaseType type) { DiscoveredDatabase db = GetTestDatabase(type); DiscoveredTable tbl = db.CreateTable("MyBulkInsertTest", new[] { new DatabaseColumnRequest("Name", new DatabaseTypeRequest(typeof(string), 10)), new DatabaseColumnRequest("Age", new DatabaseTypeRequest(typeof(int))) }); //There are no rows in the table yet Assert.AreEqual(0, tbl.GetRowCount()); using (var dt = new DataTable()) { dt.Columns.Add("Age"); dt.Columns.Add("Name"); dt.Rows.Add("50", "David"); dt.Rows.Add("60", "Jamie"); Assert.AreEqual("Age", dt.Columns[0].ColumnName); Assert.AreEqual(typeof(string), dt.Columns[0].DataType); using (IBulkCopy bulk = tbl.BeginBulkInsert()) { bulk.Timeout = 30; bulk.Upload(dt); Assert.AreEqual(2, tbl.GetRowCount()); } //columns should not be reordered Assert.AreEqual("Age", dt.Columns[0].ColumnName); Assert.AreEqual(typeof(int), dt.Columns[0].DataType); //but the data type was changed by HardTyping it } }
public void TestBulkInsert_SchemaTooNarrow_DecimalError(DatabaseType type) { DiscoveredDatabase db = GetTestDatabase(type); DiscoveredTable tbl = db.CreateTable("MyBulkInsertTest", new[] { new DatabaseColumnRequest("Id", new DatabaseTypeRequest(typeof(int))) { IsAutoIncrement = true, IsPrimaryKey = true }, new DatabaseColumnRequest("Name", new DatabaseTypeRequest(typeof(string), 10)), new DatabaseColumnRequest("Score", new DatabaseTypeRequest(typeof(decimal), null, new DecimalSize(2, 1))), new DatabaseColumnRequest("Age", new DatabaseTypeRequest(typeof(int))) }); //There are no rows in the table yet Assert.AreEqual(0, tbl.GetRowCount()); using (var dt = new DataTable()) { dt.Columns.Add("age"); dt.Columns.Add("name"); dt.Columns.Add("score"); dt.Rows.Add(60, "Jamie", 1.2); dt.Rows.Add(30, "Frank", 1.3); dt.Rows.Add(11, "Toad", 111111111.11); //bad data dt.Rows.Add(100, "King"); dt.Rows.Add(10, "Frog"); using (IBulkCopy bulk = tbl.BeginBulkInsert()) { bulk.Timeout = 30; Exception ex = null; try { bulk.Upload(dt); } catch (Exception e) { ex = e; } Assert.IsNotNull(ex, "Expected upload to fail because value on row 2 is too long"); switch (type) { case DatabaseType.MicrosoftSQLServer: StringAssert.Contains("Failed to load data row 3 the following values were rejected by the database", ex.Message); StringAssert.Contains("Parameter value '111111111.1' is out of range", ex.Message); break; case DatabaseType.MySql: Assert.AreEqual("Out of range value for column 'Score' at row 3", ex.Message); break; case DatabaseType.Oracle: StringAssert.Contains("value larger than specified precision allowed for this column", ex.Message); break; case DatabaseType.PostgreSql: StringAssert.Contains("numeric field overflow", ex.Message); break; default: throw new ArgumentOutOfRangeException(nameof(type), type, null); } } } }
public void TestBulkInsert_SchemaTooNarrow_StringError(DatabaseType type) { DiscoveredDatabase db = GetTestDatabase(type); DiscoveredTable tbl = db.CreateTable("MyBulkInsertTest", new[] { new DatabaseColumnRequest("Id", new DatabaseTypeRequest(typeof(int))) { IsAutoIncrement = true, IsPrimaryKey = true }, new DatabaseColumnRequest("Name", new DatabaseTypeRequest(typeof(string), 10)), new DatabaseColumnRequest("Age", new DatabaseTypeRequest(typeof(int))) }); //There are no rows in the table yet Assert.AreEqual(0, tbl.GetRowCount()); using (var dt = new DataTable()) { dt.Columns.Add("age"); dt.Columns.Add("name"); dt.Rows.Add(60, "Jamie"); dt.Rows.Add(30, "Frank"); dt.Rows.Add(11, "Toad"); dt.Rows.Add(50, new string('A', 11)); dt.Rows.Add(100, "King"); dt.Rows.Add(10, "Frog"); using (IBulkCopy bulk = tbl.BeginBulkInsert()) { bulk.Timeout = 30; Exception ex = null; try { bulk.Upload(dt); } catch (Exception e) { ex = e; } Assert.IsNotNull(ex, "Expected upload to fail because value on row 2 is too long"); switch (type) { case DatabaseType.MicrosoftSQLServer: StringAssert.Contains("BulkInsert failed on data row 4 the complaint was about source column <<name>> which had value <<AAAAAAAAAAA>> destination data type was <<varchar(10)>>", ex.Message); break; case DatabaseType.MySql: Assert.AreEqual("Data too long for column 'Name' at row 4", ex.Message); break; case DatabaseType.Oracle: StringAssert.Contains("NAME", ex.Message); StringAssert.Contains("maximum: 10", ex.Message); StringAssert.Contains("actual: 11", ex.Message); break; case DatabaseType.PostgreSql: StringAssert.Contains("value too long for type character varying(10)", ex.Message); break; default: throw new ArgumentOutOfRangeException(nameof(type), type, null); } } } }
public DataTable ProcessPipelineData(DataTable toProcess, IDataLoadEventListener listener, GracefulCancellationToken cancellationToken) { if (toProcess == null) { return(null); } IDatabaseColumnRequestAdjuster adjuster = null; if (Adjuster != null) { var constructor = new ObjectConstructor(); adjuster = (IDatabaseColumnRequestAdjuster)constructor.Construct(Adjuster); } //work out the table name for the table we are going to create if (TargetTableName == null) { if (string.IsNullOrWhiteSpace(toProcess.TableName)) { throw new Exception("Chunk did not have a TableName, did not know what to call the newly created table"); } TargetTableName = QuerySyntaxHelper.MakeHeaderNameSane(toProcess.TableName); } ClearPrimaryKeyFromDataTableAndExplicitWriteTypes(toProcess); StartAuditIfExists(TargetTableName); if (_loggingDatabaseListener != null) { listener = new ForkDataLoadEventListener(listener, _loggingDatabaseListener); } EnsureTableHasDataInIt(toProcess); bool createdTable = false; if (_firstTime) { bool tableAlreadyExistsButEmpty = false; if (!_database.Exists()) { throw new Exception("Database " + _database + " does not exist"); } discoveredTable = _database.ExpectTable(TargetTableName); //table already exists if (discoveredTable.Exists()) { tableAlreadyExistsButEmpty = true; if (!AllowLoadingPopulatedTables) { if (discoveredTable.IsEmpty()) { listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Warning, "Found table " + TargetTableName + " already, normally this would forbid you from loading it (data duplication / no primary key etc) but it is empty so we are happy to load it, it will not be created")); } else { throw new Exception("There is already a table called " + TargetTableName + " at the destination " + _database); } } if (AllowResizingColumnsAtUploadTime) { _dataTypeDictionary = discoveredTable.DiscoverColumns().ToDictionary(k => k.GetRuntimeName(), v => v.GetDataTypeComputer(), StringComparer.CurrentCultureIgnoreCase); } } else { listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Determined that the table name " + TargetTableName + " is unique at destination " + _database)); } //create connection to destination if (!tableAlreadyExistsButEmpty) { createdTable = true; if (AllowResizingColumnsAtUploadTime) { _database.CreateTable(out _dataTypeDictionary, TargetTableName, toProcess, ExplicitTypes.ToArray(), true, adjuster); } else { _database.CreateTable(TargetTableName, toProcess, ExplicitTypes.ToArray(), true, adjuster); } listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Created table " + TargetTableName + " successfully.")); } _managedConnection = _server.BeginNewTransactedConnection(); _bulkcopy = discoveredTable.BeginBulkInsert(_managedConnection.ManagedTransaction); if (Culture != null) { _bulkcopy.DateTimeDecider.Culture = Culture; } _firstTime = false; } try { if (AllowResizingColumnsAtUploadTime && !createdTable) { ResizeColumnsIfRequired(toProcess, listener); } //push the data swTimeSpentWritting.Start(); _affectedRows += _bulkcopy.Upload(toProcess); swTimeSpentWritting.Stop(); listener.OnProgress(this, new ProgressEventArgs("Uploading to " + TargetTableName, new ProgressMeasurement(_affectedRows, ProgressType.Records), swTimeSpentWritting.Elapsed)); } catch (Exception e) { _managedConnection.ManagedTransaction.AbandonAndCloseConnection(); if (LoggingServer != null) { _dataLoadInfo.LogFatalError(GetType().Name, ExceptionHelper.ExceptionToListOfInnerMessages(e, true)); } throw new Exception("Failed to write rows (in transaction) to table " + TargetTableName, e); } return(null); }