Login ProductsSalesSupportDownloadsAbout |
Home » Technical Support » ElevateDB Technical Support » Support Forums » ElevateDB General » View Thread |
Messages 1 to 10 of 11 total |
Locate doesn't work as expected |
Fri, Aug 16 2013 2:03 PM | Permanent Link |
Arno Garrels | Hi,
I'm still porting from DBISAM to EDB, it's not as smooth as I had expected Why does Locate('Name', 'foo ', []) return true even though there's just a record with Name = 'foo' (no trailing space)? Regards -- Arno |
Sat, Aug 17 2013 8:19 AM | Permanent Link |
Roy Lambert NLH Associates Team Elevate | Arno
>Why does Locate('Name', 'foo ', []) return true even though there's >just a record with Name = 'foo' (no trailing space)? As a guess Name is defined as a VarChar not a Char. VarChars will store the trailing space but will not take it into account when searching. At least in SQL can't remember about navigational stuff but since you have the "problem" I assume it ignores it there as well. The behaviour was (I sort of remember) a compromise after people (mainly me) complained about storing trailing spaces. There is another unfortunate effect table.FieldByName('Name').AsString = 'foo ' will return false. If my guess is right and you want trailing spaces try changing the column type to Char. Then you'll need to match the contents exactly with all the right padding (or at least I assume so - I don't use Char). Alternatively if you want the same behaviour as DBISAM check out the extensions ng for the table & query components I wrote to handle it. Roy Lambert [Team Elevate] |
Sat, Aug 17 2013 3:29 PM | Permanent Link |
Arno Garrels | Roy,
Thank you for your reply. > As a guess Name is defined as a VarChar not a Char. Correct, however doesn't matter, same behaviour with both Char and VarChar fields. > VarChars will store the trailing space but will not take it into account when searching. What a mess is this string handling, my small brain doesn't get it? IMO a space is a character as any other character as well. So when I search for "foo " (with trailing space) in a VarChar field that should not be the same as a search for "foo" (without trailing space), correct? > At least in SQL can't remember about navigational stuff but since you have the "problem" > I assume it ignores it here as well. It's a pity As it is that there's no option that truncates string-values automatically to field's size in order to avoid Exceptions when you assign a string to a string-field longer than field's size. > There is another unfortunate effect table.FieldByName('Name').AsString = 'foo ' will return false. Indeed, what a mess: if Dataset.Locate('Name', 'foo ', []) then begin if not (Dataset.FieldByName('Name').AsString = 'foo ') then raise Exception.Create('What a punk'); end; > Alternatively if you want the same behaviour as DBISAM That's all I want, with one additional feature, namely Unicode support. > check out the extensions ng > for the table & query components I wrote to handle it. Can you provide a link to that post? -- Arno |
Sun, Aug 18 2013 3:22 AM | Permanent Link |
Roy Lambert NLH Associates Team Elevate | Arno
>What a mess is this string handling, my small brain doesn't get it? IMO a space is a character as any other character as well. So when I search for "foo " (with trailing space) in a VarChar field that should not be the same as a search for "foo" (without trailing space), correct? I actually disagree totally with trailing spaces being stored. It is madness to do that, unless you also intend to have all onscreen displays or printouts to indicate there is a trailing space >It's a pity As it is that there's no option that truncates string-values automatically to field's size in order to avoid Exceptions when you assign a string to a string-field longer than field's size. Nope, but my table and wuery extensions do >> check out the extensions ng >> for the table & query components I wrote to handle it. > >Can you provide a link to that post? Not without looking, so I'll let you do that <vbg> Roy Lambert [Team Elevate] |
Sun, Aug 18 2013 7:33 AM | Permanent Link |
Michael Riley ZilchWorks | Arno Garrels wrote:
> Hi, > I'm still porting from DBISAM to EDB, it's not as smooth as I had > expected Why does Locate('Name', 'foo ', []) return true even > though there's just a record with Name = 'foo' (no trailing space)? > > Regards Arno, I got similar results within the ElevateDB Manager. I migrated Delphi's DBDemos database into ElevateDB Manager. I ran a few queries against the customer table and got some interesting results. SELECT Company FROM customer WHERE Company LIKE '%club' Returned no results ----------------- I changed the coallation of the "Company" column to be case insensitive and reran the query. ALTER TABLE "customer" ALTER COLUMN "Company" AS VARCHAR(30) COLLATE "UNI_CI" SELECT Company FROM customer WHERE Company LIKE '%club' VIP Divers Club Marmot Divers Club Makai SCUBA Club Action Club Blue Sports Club Catamaran Dive Club This is what I expected to see. ----------------- SELECT Company FROM customer WHERE Company LIKE '%club ' VIP Divers Club Marmot Divers Club Makai SCUBA Club Action Club Blue Sports Club Catamaran Dive Club This is not what I expected to see. I expected to get zero results because of the trailing space used in the LIKE clause. ----------------- SELECT Company FROM customer WHERE Company LIKE '%club_' Marmot Divers Club Makai SCUBA Club I replaced the trailing [Space] with the wildcard character and got the above results. Now, I'm thinking that there is some sort of trailing character at the end of these two records. So I modified the query one more time. ----------------- SELECT '|' + Company + '|' From customer WHERE Company LIKE '%club_' |Marmot Divers Club| |Makai SCUBA Club| When I changed to output to bracket the Company field with '|' characters there was no visible trailing character on either of these results. Interesting... perhaps Tim can shed some light on this one. -- Michael Riley GySgt USMC (Ret) www.zilchworks.com |
Sun, Aug 18 2013 2:33 PM | Permanent Link |
Arno Garrels | Roy,
> I actually disagree totally with trailing spaces being stored. It is madness to do that, unless you also intend to have all onscreen displays or printouts to indicate there is a trailing space. IMO that was possible in DBISAM and that never made a problem. Anyway my question is not about store trailing spaces but unexpected search results >It's a pity As it is that there's no option that truncates string-values automatically to field's size in order to avoid Exceptions when you assign a string to a string-field longer than field's size. > Nope, but my table and wuery extensions do I only found several versions of a nlhTable.pas that cannot prevent the truncation exception. So I gave it myself a trial today though I do not have the source of EDB at home. -- Regards {code} {**************************************************************************************************} { } { The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); } { you may not use this file except in compliance with the License. You may obtain a copy of the } { License at http://www.mozilla.org/MPL/ } { } { Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF } { ANY KIND, either express or implied. See the License for the specific language governing rights } { and limitations under the License. } { } { The helper functions for patching are Copyright (C) 2008-2009 Andreas Hausladen. } { All Rights Reserved. } { } { Portions created by Arno Garrels are Copyright (C) 2013 Arno Garrels. } { All Rights Reserved. } { } {**************************************************************************************************} {$A8,B-,C+,D+,E-,F-,G+,H+,I+,J-,K-,L+,M-,N-,O+,P+,Q-,R-,S-,T-,U-,V+,W-,X+,Y+,Z1} unit PatchPack; interface const PatchPackVersion = '1.0'; PatchPackDate = '2013/18/08'; // yyyy/dd/mm { Usage ===== Add the unit to the .dpr file's uses-list. C++Builder user can add the file to the project (Menu Project/Add to project) Example ======= uses FastMM4, // optional memory manager PatchPack, Forms, Unit1 in 'Unit1.pas'; ---------------------------------------------------------------------------- } {$Define NoEDBTruncationErrors} implementation uses Windows, SysUtils, DB; { ---------------------------------------------------------------------------- } { Helper functions, shared } type THackWideStringField = class(TWidestringField); THackStringField = class(TStringField); TJumpOfs = Integer; PPointer = ^Pointer; type PXRedirCode = ^TXRedirCode; TXRedirCode = packed record Jump: Byte; Offset: TJumpOfs; end; PWin9xDebugThunk = ^TWin9xDebugThunk; TWin9xDebugThunk = packed record PUSH: Byte; Addr: Pointer; JMP: TXRedirCode; end; PAbsoluteIndirectJmp = ^TAbsoluteIndirectJmp; TAbsoluteIndirectJmp = packed record OpCode: Word; //$FF25(Jmp, FF /4) Addr: PPointer; end; { Hooking } function GetActualAddr(Proc: Pointer): Pointer; function IsWin9xDebugThunk(AAddr: Pointer): Boolean; begin Result := (AAddr <> nil) and (PWin9xDebugThunk(AAddr).PUSH = $68) and (PWin9xDebugThunk(AAddr).JMP.Jump = $E9); end; begin if Proc <> nil then begin if (Win32Platform <> VER_PLATFORM_WIN32_NT) and IsWin9xDebugThunk(Proc) then Proc := PWin9xDebugThunk(Proc).Addr; if (PAbsoluteIndirectJmp(Proc).OpCode = $25FF) then Result := PAbsoluteIndirectJmp(Proc).Addr^ else Result := Proc; end else Result := nil; end; procedure HookProc(Proc, Dest: Pointer; var BackupCode: TXRedirCode); var n: NativeUInt; Code: TXRedirCode; begin Proc := GetActualAddr(Proc); Assert(Proc <> nil); if ReadProcessMemory(GetCurrentProcess, Proc, @BackupCode, SizeOf(BackupCode), n) then begin Code.Jump := $E9; Code.Offset := PAnsiChar(Dest) - PAnsiChar(Proc) - SizeOf(Code); WriteProcessMemory(GetCurrentProcess, Proc, @Code, SizeOf(Code), n); end; end; procedure UnhookProc(Proc: Pointer; var BackupCode: TXRedirCode); var n: NativeUInt; begin if (BackupCode.Jump <> 0) and (Proc <> nil) then begin Proc := GetActualAddr(Proc); Assert(Proc <> nil); WriteProcessMemory(GetCurrentProcess, Proc, @BackupCode, SizeOf(BackupCode), n); BackupCode.Jump := 0; end; end; procedure ReplaceVmtField(AClass: TClass; OldProc, NewProc: Pointer); type PVmt = ^TVmt; TVmt = array[0..MaxInt div SizeOf(Pointer) - 1] of Pointer; var I: Integer; Vmt: PVmt; n: NativeUInt; P: Pointer; begin OldProc := GetActualAddr(OldProc); NewProc := GetActualAddr(NewProc); I := vmtSelfPtr div SizeOf(Pointer); Vmt := Pointer(AClass); while (I < 0) or (Vmt[I] <> nil) do begin P := Vmt[I]; if (P <> OldProc) and (Integer(P) > $10000) and not IsBadReadPtr(P, 6) then P := GetActualAddr(P); if P = OldProc then begin WriteProcessMemory(GetCurrentProcess, @Vmt[I], @NewProc, SizeOf(NewProc), n); Exit; end; Inc(I); end; end; function GetDynamicMethod(AClass: TClass; Index: Integer): Pointer; asm call System.@FindDynaClass end; procedure DebugLog(const S: string); begin OutputDebugString(PChar('PatchPack installed: ' + S)); end; { End of helper functions } { **************************************************************************** } {$IFDEF NoEDBTruncationErrors} var BackupSetAsString, BackupSetAsWideString, BackupSetAsAnsiString: TXRedirCode; type TWideStringFieldFix = class(TWideStringField) protected procedure SetAsString(const Value: string); override; procedure SetAsWideString(const Value: UnicodeString); override; end; (* Not implemented yet * TStringFieldFix = class(TStringField) protected procedure SetAsAnsiString(const Value: AnsiString); override; end; procedure TStringFieldFix.SetAsAnsiString(const Value: AnsiString); var Len: Integer; PBuf: PAnsiChar; Temp: AnsiString; Buffer: array[0..dsMaxStringSize] of AnsiChar; begin if DataSize > SizeOf(Buffer) then begin SetLength(Temp, strlen(PAnsiChar(Value))+1); PBuf := PAnsiChar(Temp); Len := StrLen(PAnsiChar(Value)); end else begin PBuf := Buffer; Len := Self.Size; end; StrLCopy(PBuf, PAnsiChar(Value), Len); if Transliterate then DataSet.Translate(PBuf, PBuf, True); SetData(PBuf); end; *) procedure TWideStringFieldFix.SetAsString(const Value: string); var Val: string; begin if Length(Value) > Self.Size then Val := Copy(Value, 1, Size) else Val := Value; SetData(PChar(Val), False); end; procedure TWideStringFieldFix.SetAsWideString(const Value: UnicodeString); var Val: string; begin if Length(Value) > Self.Size then Val := Copy(Value, 1, Size) else Val := Value; SetData(PChar(Val), False); end; procedure InitEDBTruncationErrorFix; begin DebugLog('NoEDBTruncationErrors'); HookProc(@THackWideStringField.SetAsString, @TWideStringFieldFix.SetAsString, BackupSetAsString); HookProc(@THackWideStringField.SetAsWideString, @TWideStringFieldFix.SetAsWideString, BackupSetAsWideString); // HookProc(@THackStringField.SetAsAnsiString, @TStringFieldFix.SetAsAnsiString, BackupSetAsAnsiString); end; procedure FiniEDBTruncationErrorFix; begin UnhookProc(@THackWideStringField.SetAsString, BackupSetAsString); UnhookProc(@THackWideStringField.SetAsWideString, BackupSetAsWideString); // UnhookProc(@THackStringField.SetAsAnsiString, BackupSetAsAnsiString); end; {$ENDIF NoEDBTruncationErrors} { **************************************************************************** } initialization {$IFDEF NoEDBTruncationErrors} InitEDBTruncationErrorFix; {$ENDIF NoEDBTruncationErrors} finalization // In revers order {$IFDEF NoEDBTruncationErrors} FiniEDBTruncationErrorFix; {$ENDIF NoEDBTruncationErrors} end. {code} |
Mon, Aug 19 2013 3:58 AM | Permanent Link |
Roy Lambert NLH Associates Team Elevate | Arno
Thanks for letting me know that. I'll have to check the version I'm using at present with what's on the ng. If its different I'll upload the latest version for those who, like myself, don't have the source to ElevateDB. Roy Lambert |
Mon, Aug 19 2013 4:24 AM | Permanent Link |
Roy Lambert NLH Associates Team Elevate | Arno
My table component still nicely truncates, but the query component doesn't. Its a while since I wrote it, and I think I would have tested it out but obviously I haven't encountered a field overflow for a while so didn't realise it no longer worked. My guess is Tim has changed something along the way so the events I was hooking into no longer apply.I'll have to work on it Roy Lambert |
Mon, Aug 19 2013 11:46 AM | Permanent Link |
Roy Lambert NLH Associates Team Elevate | Arno
I've talked to Tim about it and my modified query component works if you're editing a sensitive result set but not for UPDATE statements. They're carried out in the bowels of the engine. Either I didn't test properly or I forgot. Roy Lambert |
Mon, Aug 19 2013 2:37 PM | Permanent Link |
Tim Young [Elevate Software] Elevate Software, Inc. timyoung@elevatesoft.com | Michael,
<< When I changed to output to bracket the Company field with '|' characters there was no visible trailing character on either of these results. Interesting... perhaps Tim can shed some light on this one. >> It's a bug with LIKE. I'll have a fix in the next build. Thanks, Tim Young Elevate Software www.elevatesoft.com |
Page 1 of 2 | Next Page » | |
Jump to Page: 1 2 |
This web page was last updated on Monday, May 6, 2024 at 03:23 PM | Privacy PolicySite Map © 2024 Elevate Software, Inc. All Rights Reserved Questions or comments ? E-mail us at info@elevatesoft.com |