1

I am having an issue with SqlBulkCopy (in c#, framework 4.5.1) where a valid XML string is causing the error System.Data.SqlClient.SqlException: {"XML parsing: line 1, character 29, A string literal was expected"}"

The table is...

CREATE TABLE [dbo].[JobManager_BigTextTest](
[PKID] [int] IDENTITY(1,1) NOT NULL,
[BigXML] [xml] NOT NULL, PK_JobManager_BigTextTest] PRIMARY KEY CLUSTERED 
(
    [PKID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [Data]
) ON [Data] TEXTIMAGE_ON [Data]

A SQL insert of the XML (which works fine) is...

INSERT INTO JobManager_BigTextTest
(
    BigXML
)
VALUES
(
    '<ArrayOfTriggerEvent xmlns="http://schemas.datacontract.org/2004/07/RRD.JobManager.AutomatedWorkScheduler.Triggers" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><TriggerEvent i:type="a:ScheduleEvent" xmlns:a="http://schemas.datacontract.org/2004/07/RRD.JobManager.AutomatedWorkScheduler.Triggers.Events"><a:Schedule i:type="b:IncrementalSchedule" xmlns:b="http://schemas.datacontract.org/2004/07/RRD.JobManager.AutomatedWorkScheduler.Schedules"><b:DaysOfMonth xmlns:c="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/><b:DaysOfWeek xmlns:c="http://schemas.datacontract.org/2004/07/System"/><b:Frequency>Daily</b:Frequency><b:LastDayOfMonth>false</b:LastDayOfMonth><b:LastExecuted i:nil="true"/><b:LastModified>2014-08-21T14:40:30.6116736-05:00</b:LastModified><b:EndTime i:nil="true"/><b:Increment>PT5M</b:Increment><b:StartTime>PT0S</b:StartTime></a:Schedule></TriggerEvent><TriggerEvent i:type="a:ScheduleEvent" xmlns:a="http://schemas.datacontract.org/2004/07/RRD.JobManager.AutomatedWorkScheduler.Triggers.Events"><a:Schedule i:type="b:SpecificSchedule" xmlns:b="http://schemas.datacontract.org/2004/07/RRD.JobManager.AutomatedWorkScheduler.Schedules"><b:DaysOfMonth xmlns:c="http://schemas.microsoft.com/2003/10/Serialization/Arrays"><c:int>8</c:int><c:int>11</c:int><c:int>24</c:int></b:DaysOfMonth><b:DaysOfWeek xmlns:c="http://schemas.datacontract.org/2004/07/System"/><b:Frequency>Monthly</b:Frequency><b:LastDayOfMonth>false</b:LastDayOfMonth><b:LastExecuted i:nil="true"/><b:LastModified>2014-08-21T14:40:30.6116736-05:00</b:LastModified><b:StartTimes xmlns:c="http://schemas.microsoft.com/2003/10/Serialization/Arrays"><c:duration>PT11H</c:duration><c:duration>PT11H30M</c:duration><c:duration>PT13H30M</c:duration></b:StartTimes></a:Schedule></TriggerEvent></ArrayOfTriggerEvent>'
)

The c# code that I used to create an empty DataTable is...

public static DataTable GetDataTableFromSqlDestination(string tableName)
{
    tableName = MakeInjectionProof(tableName); // error if injection discovered
    var dataTable = new DataTable();
    var query = $"SELECT * FROM [{tableName}] WHERE 1 = 0";

    using (var connection = new SqlConnection("my_connection"))
    using (var command = new SqlCommand(query, connection))
    {
        command.CommandTimeout = connection.ConnectionTimeout;
        command.CommandType = CommandType.Text;
        connection.Open();

        var da = new SqlDataAdapter(command);

        da.FillSchema(dataTable, SchemaType.Mapped);

        connection.Close();

        dataTable.PrimaryKey = null; // strip off primary key
        dataTable.Columns.Remove("PKID");
    }

    return dataTable;
}

After adding a row (or rows) to the DataTable, the c# method doing the bulk copy is is called...

public static void BulkCopyProcessChunk
(
    string tableName,
    DataTable dataTable,
    SqlConnection connection,
    SqlTransaction transaction
)
{
    using (var sbc = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, transaction))
    {
        sbc.BulkCopyTimeout = 0; // Indefinite time out
        sbc.DestinationTableName = tableName;

        sbc.BatchSize = dataTable.Rows.Count;

        foreach (DataColumn r in dataTable.Columns)
        {
            sbc.ColumnMappings.Add(r.ColumnName, r.ColumnName);
        }

        sbc.WriteToServer(dataTable); // <--- error occurs here
    }
}

The XML DataColumn, BigXML, has a datatype of System.String with a max length of -1. Can anyone tell me what is going on here?

Shnugo
  • 66,100
  • 9
  • 53
  • 114
Sam Jazz
  • 131
  • 7
  • The best thing to do is to run query in SQL Server Management Studio (SSMS) which comes with SQL Server. The error message as 100 times better than in c#. With tables in c# a -1 usually occurs because the table isn't constructed, or there are no columns in the table. Make sure you are not calling the code from the class.form constructor. It should be in the form load method after the class is constructed. – jdweng Dec 13 '16 at 16:36
  • I ran the query, as posted above to insert the exact same string into the same table, and there does not appear to be anything wrong with the table or the string – Sam Jazz Dec 13 '16 at 17:15

1 Answers1

1

The error message points to line 1, character 29...

At this point the default-namespace-attribute expects a string literal... You are providing the namespace in double qoutes. So everything seems to be OK, but:

There are several posts (e.g. this one) pointing to problems in connection with SqlBulkCopy and double qoutes.

You can try the following:

  • Use single qoutes instead of the doubled: <ArrayOfTriggerEvent xmlns='Your namespace' NextAttr='SomeVAlue' ...

  • Try to escape the "-character. Typically this is done by either doubling the sign (xmlns=""Your namespace""), or with an escape character. Try \", ^" or the Backtick (`")...

Some more information on Escape Characters

Community
  • 1
  • 1
Shnugo
  • 66,100
  • 9
  • 53
  • 114