Board index » delphi » Problem with Locate in IBX45

Problem with Locate in IBX45

I've found a problem using Locate in a TIBDataset with the new version IBX45
Next variants of using function Locate have problems:
1. IBDataSet.Locate('COD', null, [...]);  for Lookup fields when data KEY
fields  is null
2. IBDataSet.Locate('COD', VarArrayOf('111'), [...]);  for one field and
search data as VarArray
3. IBDataSet.Locate('COD;NAME', .....); for count field names more than 1
----------------------------
For correct work of function TIBCustomDataSet. InternalLocate I was
compelled to change an initial code.
At modification I used the appropriate text of the version IBX442.
Jeff,  please, look critically at the following code and tell your opinion.
Your change ( result := result and (AnsiPos(val[i], fld_str) = 1)  ) I use
in my text.
-----------------------------
function TIBCustomDataSet.InternalLocate(const KeyFields: string;
  const KeyValues: Variant; Options: TLocateOptions): Boolean;
var
  fl: TList;
  CurBookmark: string;
  fld : Variant;
  val : Array of Variant;
  i, fld_cnt: Integer;
  fld_str : String;
begin
  fl := TList.Create;
  result := False; // before GetFieldList(fl, KeyFields) if bad field name
  try
    GetFieldList(fl, KeyFields);
    fld_cnt := fl.Count;
    CurBookmark := Bookmark;
    SetLength(val, fld_cnt);
    if not Eof then
      for i := 0 to fld_cnt - 1 do
      begin
        if (fld_cnt > 1) or VarIsArray(KeyValues) then // Alex   (for case
#2 and #3)
          val[i] := KeyValues[i] // Alex
        else                             // Alex
          val[i] := KeyValues;   // Alex

        if not VarIsNull(val[i]) then // Alex add
        begin
          try
            VarAsType(TField(fl[i]).Value, VarType(val[i]));
          except
            on E: EVariantError do
            begin
              result := False;
              raise;
            end;
          end;
          if TField(fl[i]).DataType = ftString then
          begin
            if (loCaseInsensitive in Options) then
              val[i] := AnsiUpperCase(val[i]);
            val[i] := TrimRight(val[i]);
          end;
        end; // Alex add
      end;

    while ((not result) and (not EOF) and (fld_cnt > 0)) do   // alex add
(fld_cnt > 0)
    begin
      i := 0;
      result := True;
      while (result and (i < fld_cnt)) do
      begin
        fld := TField(fl[i]).Value;
        if VarIsNull(fld) then
          result := result and VarIsNull(val[i])
        else
        begin //  Alex add
          result := not (VarIsNull(val[i])); // Alex add
          if result then
          begin //  Alex add
            if TField(fl[i]).DataType = ftString then
            begin
              fld_str := TField(fl[i]).AsString;
              fld_str := TrimRight(fld_str);
              if (loCaseInsensitive in Options) then
                fld_str := AnsiUpperCase(fld_str);
              if (loPartialKey in Options) then
                  result := result and (AnsiPos(val[i], fld_str) = 1) //
Jeff fix
              else
                  result := result and (fld_str = val[i]);
            end
            else
              result := result and (val[i] = fld);
          end; //  Alex add
        end; //  Alex add
        Inc(i);
      end;
      if not result then
        Next;
    end;
    if not result then
      Bookmark := CurBookmark
    else
      CursorPosChanged;
  finally
    fl.Free;
    val := nil;
  end;
end;

-----------
Alexandr Golubev

 

Re:Problem with Locate in IBX45


This is the changed version as of yesterday.  You can test it.  BTW, while your
#2 does work with this version, technically it is not supposed to (try the BDE
with that type of Locate and you will also get an invalid variant exception just
like IBX).  It is valid to pass VarArrays only with multiple column lookups as
per the help.  Both IBX and the BDE raise exceptions passing a VarArray for a
single field locate.  

function TIBCustomDataSet.InternalLocate(const KeyFields: string;
  const KeyValues: Variant; Options: TLocateOptions): Boolean;
var
  fl: TList;
  CurBookmark: string;
  fld : Variant;
  val : Array of Variant;
  i, fld_cnt: Integer;
  fld_str : String;
begin
  fl := TList.Create;
  try
    GetFieldList(fl, KeyFields);
    fld_cnt := fl.Count;
    CurBookmark := Bookmark;
    result := False;
    SetLength(val, fld_cnt);
    if not Eof then
      for i := 0 to fld_cnt - 1 do
      begin
        if VarIsArray(KeyValues) then
          val[i] := KeyValues[i]
        else
          val[i] := KeyValues;
        if (TField(fl[i]).DataType = ftString) and
           not VarIsNull(val[i]) then
        begin
          if (loCaseInsensitive in Options) then
            val[i] := AnsiUpperCase(val[i]);
          val[i] := TrimRight(val[i]);
        end;
      end;
    while ((not result) and (not EOF)) do
    begin
      i := 0;
      result := True;
      while (result and (i < fld_cnt)) do
      begin
        fld := TField(fl[i]).Value;
        if VarIsNull(fld) then
          result := result and VarIsNull(val[i])
        else
          if result then
          begin
            try
              fld := VarAsType(fld, VarType(val[i]));
            except
              on E: EVariantError do result := False;
            end;
            if TField(fl[i]).DataType = ftString then
            begin
              fld_str := TField(fl[i]).AsString;
              fld_str := TrimRight(fld_str);
              if (loCaseInsensitive in Options) then
                fld_str := AnsiUpperCase(fld_str);
              if (loPartialKey in Options) then
                result := result and (AnsiPos(val[i], fld_str) = 1)
              else
                result := result and (fld_str = val[i]);
            end
            else
              result := result and (val[i] = fld);
          end;
        Inc(i);
      end;
      if not result then
        Next;
    end;
    if not result then
      Bookmark := CurBookmark
    else
      CursorPosChanged;
  finally
    fl.Free;
    val := nil;
  end;
end;

Quote
Alexandr Golubev wrote:

--
Jeff Overcash (TeamB)
      (Please do not email me directly unless  asked. Thank You)
The correct way to punctuate a sentence that starts: "Of course it is
none of my business but ~" is to place a period after the word "but".
Don't use excessive force in supplying such a moron with a period.
Cutting his throat is only a momentary pleasure and is bound to get
you talked about.   (RAH)

Re:Problem with Locate in IBX45


Jeff, thank for the answer and help.
Alexandr Golubev

Quote
> This is the changed version as of yesterday.  You can test it.  BTW, while
your
> #2 does work with this version, technically it is not supposed to (try the
BDE
> with that type of Locate and you will also get an invalid variant
exception just
> like IBX).  It is valid to pass VarArrays only with multiple column
lookups as
> per the help.  Both IBX and the BDE raise exceptions passing a VarArray
for a
> single field locate.

Re:Problem with Locate in IBX45


Just turn off run time packages and add the $(DELPHI)\source\vcl directory to
the unit search path and it should pick it up.

Please watch the over quoting.  Thanks.

Quote
Mike Noordermeer wrote:

> Jeff,

> We are also experiencing the 'locate' problem. I have included your code
> snippet - but how do I rebuild the IBX components? Thanks.

> Kind regards

> Mike

--
Jeff Overcash (TeamB)
      (Please do not email me directly unless  asked. Thank You)
The correct way to punctuate a sentence that starts: "Of course it is
none of my business but ~" is to place a period after the word "but".
Don't use excessive force in supplying such a moron with a period.
Cutting his throat is only a momentary pleasure and is bound to get
you talked about.   (RAH)

Re:Problem with Locate in IBX45


Jeff,

We are also experiencing the 'locate' problem. I have included your code
snippet - but how do I rebuild the IBX components? Thanks.

Kind regards

Mike

"Jeff Overcash (TeamB)" <overc...@onramp.net> wrote in message
news:3A992657.5A1CE050@onramp.net...

Quote
> This is the changed version as of yesterday.  You can test it.  BTW, while
your
> #2 does work with this version, technically it is not supposed to (try the
BDE
> with that type of Locate and you will also get an invalid variant
exception just
> like IBX).  It is valid to pass VarArrays only with multiple column
lookups as
> per the help.  Both IBX and the BDE raise exceptions passing a VarArray
for a
> single field locate.

> function TIBCustomDataSet.InternalLocate(const KeyFields: string;
>   const KeyValues: Variant; Options: TLocateOptions): Boolean;
> var
>   fl: TList;
>   CurBookmark: string;
>   fld : Variant;
>   val : Array of Variant;
>   i, fld_cnt: Integer;
>   fld_str : String;
> begin
>   fl := TList.Create;
>   try
>     GetFieldList(fl, KeyFields);
>     fld_cnt := fl.Count;
>     CurBookmark := Bookmark;
>     result := False;
>     SetLength(val, fld_cnt);
>     if not Eof then
>       for i := 0 to fld_cnt - 1 do
>       begin
>         if VarIsArray(KeyValues) then
>           val[i] := KeyValues[i]
>         else
>           val[i] := KeyValues;
>         if (TField(fl[i]).DataType = ftString) and
>            not VarIsNull(val[i]) then
>         begin
>           if (loCaseInsensitive in Options) then
>             val[i] := AnsiUpperCase(val[i]);
>           val[i] := TrimRight(val[i]);
>         end;
>       end;
>     while ((not result) and (not EOF)) do
>     begin
>       i := 0;
>       result := True;
>       while (result and (i < fld_cnt)) do
>       begin
>         fld := TField(fl[i]).Value;
>         if VarIsNull(fld) then
>           result := result and VarIsNull(val[i])
>         else
>           if result then
>           begin
>             try
>               fld := VarAsType(fld, VarType(val[i]));
>             except
>               on E: EVariantError do result := False;
>             end;
>             if TField(fl[i]).DataType = ftString then
>             begin
>               fld_str := TField(fl[i]).AsString;
>               fld_str := TrimRight(fld_str);
>               if (loCaseInsensitive in Options) then
>                 fld_str := AnsiUpperCase(fld_str);
>               if (loPartialKey in Options) then
>                 result := result and (AnsiPos(val[i], fld_str) = 1)
>               else
>                 result := result and (fld_str = val[i]);
>             end
>             else
>               result := result and (val[i] = fld);
>           end;
>         Inc(i);
>       end;
>       if not result then
>         Next;
>     end;
>     if not result then
>       Bookmark := CurBookmark
>     else
>       CursorPosChanged;
>   finally
>     fl.Free;
>     val := nil;
>   end;
> end;

> Alexandr Golubev wrote:

> --
> Jeff Overcash (TeamB)
>       (Please do not email me directly unless  asked. Thank You)
> The correct way to punctuate a sentence that starts: "Of course it is
> none of my business but ~" is to place a period after the word "but".
> Don't use excessive force in supplying such a moron with a period.
> Cutting his throat is only a momentary pleasure and is bound to get
> you talked about.   (RAH)

Re:Problem with Locate in IBX45


The new edition of function InternalLocate works without problems. A thank,
Jeff.

I have small offer on addition of the new text:
in    IBCustomDataSet.InternalLocate change
  if (loPartialKey in Options) then
    result := result and (AnsiPos(val[i], fld_str) = 1)
to
  if (loPartialKey in Options) and (not VarIsNull(val[i])) then
    result := result and (AnsiPos(val[i], fld_str) = 1)

I think, that it will raise reliability of work in such case: IBDataSet.
Locate ('NAME', null, [loPartialKey]);

Thank for attention.
Alexandr Golubev.

Re:Problem with Locate in IBX45


Hi Jeff

Will you update 4.5 or will it be 4.51 for this? I believe lots of people
are using this lookup thingy... ?

Thanks anyhow

"Jeff Overcash (TeamB)" <overc...@onramp.net> wrote in message
news:3A999CA3.83585890@onramp.net...

Quote
> Just turn off run time packages and add the $(DELPHI)\source\vcl directory
to
> the unit search path and it should pick it up.

Other Threads