Delphi Firedac Oracle:定位主键(VARCHAR 或 VARCHAR2)时引发异常
Delphi Firedac Oracle : Raises Exception When Locating Primary key (VARCHAR or VARCHAR2)
Oracle 的示例 table
create table appval (
id varchar2(4) not null primary key,
val1 number(38,0) default 0,
val2 number(5,2) default 0);
insert into appval (id,val1) values ('1101', 1500000);
insert into appval (id,val2) values ('1102', 2.5);
delphi (Rad Studio) 示例
type
TValHelper = class (TComponent)
private
FDataSet: TFDTable;
protected
procedure PrepareTable;
public
constructor CreateHelper(AOwner: TComponent; var ATable: TFDTable); reintroduce;
function GetVal1(AId: string): Currency;
function GetVal2(AId: string): Double;
end;
constructor CreateHelper(AOwner: TComponent; var ATable: TFDTable);
begin
inherited Create(AOwner);
if not Assigned(ATable) then
Raise Exception.Create('Null Parameter passed.');
FDataSet := ATable;
PrepareTable;
end;
procedure TValHelper.PrepareTable;
begin
if not FDataSet.Active then
begin
FDataSet.Connection := Dm.FDConnection;
FDataSet.TableName := 'appval';
FDataSet.Open;
end;
end;
function TValHelper.GetVal1 (AId: string): Currency;
begin
Result := 0; {default value if false}
if AppVal.Locate('id', AId,
[loCaseInsensitive, loPartialKey]) then {<-- Exception}
Result := AppNumVal.Fields[1].AsCurrency;
end;
function TValHelper.GetVal2 (AId: string): Double;
begin
Result := 0; {default value if false}
if AppVal.Locate('id', AId,
[loCaseInsensitive, loPartialKey]) then {<-- Exception}
Result := AppNumVal.Fields[2].AsFloat;
end;
当我在内部调用 GetVal1 函数时 "Locate" 使用消息引发异常
Exception class EFDException with message '[FireDAC][Phys][Ora]-345.
Data too large for variable
[:FD__LC_ID]. Max len = [4], actual len = [5] Hint:
set the TFDParam.Size to a greater value'.
我尝试用其他 DB(SQLite) 重现这个测试,没有像 oracle 那样引发异常。
这是错误或我的代码中缺少某些内容。谁能解释一下。
我做了一个研究并试图追踪这个错误
我降落在 FireDac.Comp.Client.pas 的可疑街区
(Delphi 东京 10.2)
{LINE 12690}
procedure TFDTable.FetchWindow
begin
{some code}
{line 12769 i Set Watch at Command.CommandText.Text}
Command.CommandText.Add(GenerateSQL);
{Watch value :
'SELECT A.*, A.ROWID AS FD__ROWID'
'FROM APPVAL A'
'WHERE ({FN UCASE(A.ID)} LIKE {FN UCASE(:FD__LC_ID)})'
'ORDER BY A.ID ASC'
'{LIMIT(1)}'
:F__LC_ID <-- is param with size 4
until this
everything goes fine.
}
// check locate params {LINE 12785}
else if IsPrefixed(oParam.Name, C_FD_CmdGenLocate, sField) then begin
oParam.AssignFieldValue(FieldByName(sField), GetLocateRow.ValueS[sField]);
// made LIKE compatible String
if FTableParams.FLocatePartial and
(oParam.DataType in [ftString, ftWideString, ftFixedChar, ftFixedWideChar]) then
oParam.Value := VarToStr(oParam.Value) + '%'; {LINE 12791}
{
something wrong with this oParam.Value Plus 1 char '%'
and i assume field has only 4 so if we increase the field size
manualy value will be padded with space before '%' so this will
still produce exception (oParam.Value always greater +1).
}
end
end;
我该如何解决这个问题。
我们可以称之为错误。当附加 % 字符时,FireDAC 可能会增加参数的限制大小。但是,在您的情况下,您似乎希望通过确切的术语而不是部分来定位记录。如果是这样,只需排除 loPartialKey flag from your Locate 方法调用。如果没有,您可以自己 trim 一个字符的搜索词作为快速肮脏的解决方法。
Oracle 的示例 table
create table appval (
id varchar2(4) not null primary key,
val1 number(38,0) default 0,
val2 number(5,2) default 0);
insert into appval (id,val1) values ('1101', 1500000);
insert into appval (id,val2) values ('1102', 2.5);
delphi (Rad Studio) 示例
type
TValHelper = class (TComponent)
private
FDataSet: TFDTable;
protected
procedure PrepareTable;
public
constructor CreateHelper(AOwner: TComponent; var ATable: TFDTable); reintroduce;
function GetVal1(AId: string): Currency;
function GetVal2(AId: string): Double;
end;
constructor CreateHelper(AOwner: TComponent; var ATable: TFDTable);
begin
inherited Create(AOwner);
if not Assigned(ATable) then
Raise Exception.Create('Null Parameter passed.');
FDataSet := ATable;
PrepareTable;
end;
procedure TValHelper.PrepareTable;
begin
if not FDataSet.Active then
begin
FDataSet.Connection := Dm.FDConnection;
FDataSet.TableName := 'appval';
FDataSet.Open;
end;
end;
function TValHelper.GetVal1 (AId: string): Currency;
begin
Result := 0; {default value if false}
if AppVal.Locate('id', AId,
[loCaseInsensitive, loPartialKey]) then {<-- Exception}
Result := AppNumVal.Fields[1].AsCurrency;
end;
function TValHelper.GetVal2 (AId: string): Double;
begin
Result := 0; {default value if false}
if AppVal.Locate('id', AId,
[loCaseInsensitive, loPartialKey]) then {<-- Exception}
Result := AppNumVal.Fields[2].AsFloat;
end;
当我在内部调用 GetVal1 函数时 "Locate" 使用消息引发异常
Exception class EFDException with message '[FireDAC][Phys][Ora]-345.
Data too large for variable
[:FD__LC_ID]. Max len = [4], actual len = [5] Hint:
set the TFDParam.Size to a greater value'.
我尝试用其他 DB(SQLite) 重现这个测试,没有像 oracle 那样引发异常。
这是错误或我的代码中缺少某些内容。谁能解释一下。
我做了一个研究并试图追踪这个错误 我降落在 FireDac.Comp.Client.pas 的可疑街区 (Delphi 东京 10.2)
{LINE 12690}
procedure TFDTable.FetchWindow
begin
{some code}
{line 12769 i Set Watch at Command.CommandText.Text}
Command.CommandText.Add(GenerateSQL);
{Watch value :
'SELECT A.*, A.ROWID AS FD__ROWID'
'FROM APPVAL A'
'WHERE ({FN UCASE(A.ID)} LIKE {FN UCASE(:FD__LC_ID)})'
'ORDER BY A.ID ASC'
'{LIMIT(1)}'
:F__LC_ID <-- is param with size 4
until this
everything goes fine.
}
// check locate params {LINE 12785}
else if IsPrefixed(oParam.Name, C_FD_CmdGenLocate, sField) then begin
oParam.AssignFieldValue(FieldByName(sField), GetLocateRow.ValueS[sField]);
// made LIKE compatible String
if FTableParams.FLocatePartial and
(oParam.DataType in [ftString, ftWideString, ftFixedChar, ftFixedWideChar]) then
oParam.Value := VarToStr(oParam.Value) + '%'; {LINE 12791}
{
something wrong with this oParam.Value Plus 1 char '%'
and i assume field has only 4 so if we increase the field size
manualy value will be padded with space before '%' so this will
still produce exception (oParam.Value always greater +1).
}
end
end;
我该如何解决这个问题。
我们可以称之为错误。当附加 % 字符时,FireDAC 可能会增加参数的限制大小。但是,在您的情况下,您似乎希望通过确切的术语而不是部分来定位记录。如果是这样,只需排除 loPartialKey flag from your Locate 方法调用。如果没有,您可以自己 trim 一个字符的搜索词作为快速肮脏的解决方法。