Уважаемые профессионалы!
Для простоты описания проблемы пример несколько гипотетичен.
На форе расположены:
TDatabase, подлюченный к MS Access через ODBC-драйвер,
TTable, TProvider, TClientDataSet.
При вызове ApllyUpdates после добавлении записей в TClientDataSet
возникает ошибка:
> Invalid field name.
> [Microsoft][Драйвер ODBC Microsoft Access] Инструкция INSERT INTO содержит неизвестное имя поля 'CLASS.ID'.
> Прверьте, что ...
Очевидно MS Access не понимает синтаксиса CLASS.ID при выполнении операции INSERT,
поле ID в таблице CLASS существует.
Изменение и удаление записей такой ошибки не вызывают.
При использованиии вместо ODBC драйвера Native драйвера BDE таких проблем не возникает, но
возникают другие, ...

Поэтому хотелось бы услышать совета по решению проблемы связки
BDE->ODBC->Access.
На само деле — это большой проект на Delphi 3
c поддержкой нескольких баз данных, и т.д. и в ходе
развития проекта заказчику потребовалась поддержка MS Access!
Использование BDE заложено в основе проекта и изменить это невозможно,
как бы не хотелось

Я пробывал то же самое на Delphi 7 — все работает, но проект то на Delphi 3,
и с этим то же ничего нельзя поделать.
Проблема разрешилась перекрытием метода ApplyUpdates в провайдере.
Решение не лишено недостатков, но по крайней мере это работает.
function TMyProvider.ApplyUpdates(Delta: OleVariant; MaxErrors: Integer;
out ErrorCount: Integer): OleVariant;
var
ds: TClientdataSet;
i: Integer;
qUp: TQuery; // TQuery для выполнения запроса на добавление
sql: String; // текст запроса на добавление записей
fl: TStrings; // список имен полей
tn: String; // имя таблицы
// True - если все записи в Delta на добавление
function _usok: Boolean;
begin
Result := True;
ds.First;
while Result and not ds.EOF do
begin
Result := (ds.UpdateStatus = usInserted);
ds.Next;
end;
end;
// выделить имя таблицы, к которой привязан провайдер
// пустая строка если неудача (несколько таблиц в select)
function _etn: String;
var
s: TStrings;
begin
Result := '';
if DataSet is TTable then
Result := TTable(DataSet).TableName
else
if DataSet is TQuery then
begin
// процедура SQLExtractDependedTables выделяет имена таблиц учавствующих в запросе
s := SQLExtractDependedTables(TQuery(DataSet).SQL.Text);
try
if (s.Count = 1) then
Result := s[0];
finally
s.Free;
end;
end;
end;
// построить список полей
function _bfl: TStrings;
var
i: Integer;
begin
Result := TStringList.Create;
for i := 0 to ds.FieldCount-1 do
Result.AddObject(ds.Fields[i].FieldName, ds.Fields[i]);
end;
begin
ds := TClientdataSet.Create(nil);
try
ds.Data := Delta;
tn := _etn;
// если запрос
if (tn <> '') and _usok then
try
qUp := TQuery.Create(nil);
try
// привязка к базе данных
qUp.SessionName := DataSet.SessionName;
qUp.DatabaseName := DataSet.DatabaseName;
sql := Format('INSERT INTO %s (', [tn]);
// формируем SQL на добавление
fl := _bfl;
try
// поля
for i := 0 to fl.Count-2 do
sql := sql + fl[i] + ',';
sql := sql + fl[fl.Count-1] + ') VALUES (';
// параметры
for i := 0 to fl.Count-2 do
sql := sql + ':' + fl[i] + ',';
sql := sql + ':' + fl[fl.Count-1] + ')';
qUp.SQL.Text := sql;
qUp.Prepare;
// по всем записям
ds.First;
while not ds.EOF do
begin
// заполняем параметры
for i := 0 to fl.Count-1 do
qUp.ParamByName(fl[i]).AssignField(TField(fl.Objects[i]));
// добавляем запись
qUp.ExecSQL;
// перход к следующей записи
ds.Next;
end;
// все хорошо - очищаем Delta
Delta := null;
finally
fl.Free;
end;
finally
qUp.Free;
end;
except
// ошибка при добавлении записи ???
end;
if Not VarIsNull(Delta) then
Result := inherited ApplyUpdates(Delta, maxErrors, ErrorCount)
else
Result := null;
finally
ds.Free;
end;
end;