BUG: CommandBuilder updates do not succeed because of non-ANSI syntax (326602)
The information in this article applies to:
- Microsoft Visual Studio .NET (2002), Professional Edition
- Microsoft Visual Studio .NET (2002), Enterprise Architect Edition
- Microsoft Visual Studio .NET (2002), Enterprise Developer Edition
- Microsoft Visual Studio .NET (2002), Academic Edition
This article was previously published under Q326602 SYMPTOMS When you use the System.Data.OleDb.OleDbCommandBuilder class in OLE DB .NET Provider to automatically generate INSERT,
DELETE, or UPDATE statements in an application, the application may not update
the data with some OLE DB providers. The error message that you receive depends
on which OLE DB provider that you use, but the message indicates that the
statement that is used has incorrect syntax. For example, the error message
that you receive from the IBM AS400 OLE DB Provider is as follows:
System.Data.OleDb.OleDbException: SQL0417: Combination
of parameter markers not valid. Cause . . . . . : The statement string
specified as the object of a PREPARE statement contains a predicate or
expression where parameter markers have been used as operands of the same
operator. The following restrictions apply to the use of parameter markers: --
Both the operands in a predicate cannot be parameter markers. For example,
specifying predicates of the form: ? = ? or ? = ( SELECT ? FROM x ) are not
valid. -- Both the operands in a expression cannot be parameter markers. For
example, specifying an expression of the form: ? + ? is not valid. -- At least
one of the operands in the BETWEEN predicate cannot be a parameter marker. For
example, specifying the predicate of the form: ? BETWEEN ? and ? is not valid.
-- At least, one of the operands of the IN predicate must not be a parameter
marker. For example, specifying the predicate of the form: ? IN (?, ?, ?) is
not valid. Recovery . . . : Correct the statement so that all operands of the
predicate or expression are not parameter markers. Try the request again.
The following OLE DB providers do not update because of incorrect
syntax:
- IBM AS/400 OLE DB Provider
- Informix OLE DB Provider
CAUSE The OLE DB .NET Data Provider generates non-ANSI compliant
syntax for the WHERE clause of the commands that include the following clause:
? IS NULL
STATUSMicrosoft has confirmed that this is a bug in the Microsoft
products that are listed at the beginning of this article.
MORE INFORMATIONSteps to Reproduce the Behavior The following Microsoft Visual C# sample code demonstrates the
problem:
DataSet ds = new DataSet();
String cnStr = "Provider=IBMDA400.DataSource.1;Password=PWD;Persist Security Info=True;User ID=USER;Data Source=DataSource";
OleDbConnection cn = new OleDbConnection(cnStr);
OleDbDataAdapter da = new OleDbDataAdapter("select id,stringcol from schema.table1", cn);
OleDbCommandBuilder builder = new OleDbCommandBuilder(da);
OleDbCommand insert = new OleDbCommand("", cn);
OleDbCommand deleteAll = new OleDbCommand("DELETE FROM schema.table1", cn);
int j;
try
{
cn.Open();
deleteAll.ExecuteNonQuery();
for (j = 0; j<4; j++)
{
insert.CommandText = "INSERT INTO schema.table1 (id,stringcol) VALUES (" + j.ToString() + ",'string" + j.ToString() + "')";
if ( j==1)
{
insert.CommandText = "INSERT INTO schema.table1 (id) VALUES (" + j.ToString() + ")";
}
insert.ExecuteNonQuery();
}
da.FillSchema(ds, SchemaType.Source, "table1");
da.Fill(ds, "table1");
OleDbCommand update = builder.GetUpdateCommand();
ds.Tables[0].Rows[0]["stringcol"] = "New Value";
ds.Tables[0].Rows[1]["stringcol"] = "New Value2";
int i = da.Update(ds, "table1");
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
The table that is used for this code has the following format:
CREATE TABLE table1
(
id int,
stringcol varchar(20),
PRIMARY KEY(id)
)
Workaround Use one of the following methods to work around the problem:
- Method 1: Do not use the CommandBuilder to automatically generate INSERT, DELETE, or UPDATE commands.
Generate the commands explicitly instead.
- Method 2: Modify the command object that is generated by
the CommandBuilder to modify the text and the parameters of the command.
The following code demonstrates one way to modify the command
object that is generated by the CommandBuilder to update successfully:
DataSet ds = new DataSet();
String cnStr = "Provider=IBMDA400.DataSource.1;Password=PWD;Persist Security Info=True;User ID=USER;Data Source=DataSource";
OleDbConnection cn = new OleDbConnection(cnStr);
OleDbDataAdapter da = new OleDbDataAdapter("select id,stringcol from schema.table1", cn);
OleDbCommandBuilder builder = new OleDbCommandBuilder(da);
OleDbCommand insert = new OleDbCommand("", cn);
OleDbCommand deleteAll = new OleDbCommand("DELETE FROM schema.table1", cn);
int j;
try
{
cn.Open();
deleteAll.ExecuteNonQuery();
for (j = 0; j<4; j++)
{
insert.CommandText = "INSERT INTO schema.table1 (id,stringcol) VALUES (" + j.ToString() + ",'string" + j.ToString() + "')";
if ( j==1)
{
insert.CommandText = "INSERT INTO schema.table1 (id) VALUES (" + j.ToString() + ")";
}
insert.ExecuteNonQuery();
}
da.FillSchema(ds, SchemaType.Source, "table1");
da.Fill(ds, "table1");
OleDbCommand update = builder.GetUpdateCommand();
update.CommandText =
"UPDATE schema.table1 SET ID = ? , STRINGCOL = ? WHERE" +
"( (ID = ?) AND ( ( (?=1) AND STRINGCOL IS NULL) OR (STRINGCOL = ?)))";
update.Connection = cn;
OleDbParameter p = update.Parameters[3];
p.DbType = DbType.Int32;
p.OleDbType = OleDbType.Integer;
p.SourceColumn = "";
OleDbDataAdapter da2 = new OleDbDataAdapter();
da2.UpdateCommand = update;
da2.RowUpdating += new System.Data.OleDb.OleDbRowUpdatingEventHandler(this.MyOleDbRowUpdatingEventHandler);
ds.Tables[0].Rows[0]["stringcol"] = "New Value";
ds.Tables[0].Rows[1]["stringcol"] = "New Value2";
int i = da2.Update(ds, "table1");
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
The command text is modified and replaces the following:
? IS NULL
with:
(?=1)
You must also modify the corresponding parameter to change its type to
an Integer. Set the value to 0 if the original value of STRINGCOL was non-null,
or to 1 if it was null:
public void MyOleDbRowUpdatingEventHandler( object sender,OleDbRowUpdatingEventArgs e)
{
OleDbDataAdapter da = (OleDbDataAdapter) sender;
Object o = e.Row["stringcol", DataRowVersion.Original];
if (o is System.DBNull)
{
da.UpdateCommand.Parameters[3].Value = 1;
}
else
{
da.UpdateCommand.Parameters[3].Value = 0;
}
}
Modification Type: | Minor | Last Reviewed: | 9/13/2005 |
---|
Keywords: | kbvs2002sp1sweep kbbug kbfix KB326602 |
---|
|