Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[REQ] [ByName]AsBytes #4

Open
Alekcvp opened this issue Jun 22, 2017 · 9 comments
Open

[REQ] [ByName]AsBytes #4

Alekcvp opened this issue Jun 22, 2017 · 9 comments

Comments

@Alekcvp
Copy link

Alekcvp commented Jun 22, 2017

Is it possible to add properties Fields.ByNameAsBytes : TBytes and Fields.AsBytes : TBytes for accessing Char|VarChar fields with OCTETS encoding? Since RawByteString is not always suitable (and is not recommended for use by Embarcadero).

@the-Arioch
Copy link
Owner

EMBT tried to remove strings, then introuced them back.
You can just add a class helper over TSQLDA that takes RawByteString and copies it into TBytes. Yep, not most efficient.

I just looked into all them - TSQLDA.SetAsRawByteString and TSQLDA.GetAsRawByteString and TSQLResult.GetAsRawByteString and TSQLParams.SetAsRawByteString

a bit too many copy-paste already and i am not sure how to properly make the .SetAsBytes routine with all the non-blob and non-char types.

not for a fast hack, definitely :-)

@Alekcvp
Copy link
Author

Alekcvp commented Jun 23, 2017

I've done it already in this way for only SQL_TEXT and SQL_VARYING types. Read/WriteBlob already have methods for Pointers.

@the-Arioch
Copy link
Owner

Quick and ugly hack, for a whie

type TSQLDA_Bytes = class helper for TSQLDA
  protected
    function GetAsBytes(const Index: Word): TBytes;
    function GetByNameAsBytes(const name: string): TBytes;
  public
    property AsBytes[const Index: Word]: TBytes  read GetAsBytes;
    property ByNameAsBytes[const name: string]: TBytes read GetByNameAsBytes;
end;

function TSQLDA_Bytes.GetAsBytes(const Index: Word): TBytes;
var rbs: RawByteString;
begin
  Result := nil; // break out of many-references-to-same-array problem, if any
  rbs := GetAsRawByteString(Index);

  if rbs > '' then begin
     SetLength(Result, Length(rbs));
     Move( PAnsiChar(rbs)^, Result[Low(Result)], Length(rbs) );
  end;
end;

function TSQLDA_Bytes.GetByNameAsBytes(const name: string): TBytes;
begin
  Result := GetAsBytes(GetFieldIndex(AnsiString(Name)));
end;

@the-Arioch
Copy link
Owner

But blobs are not regular fields, they are not numbers, they ae not dates, etc....

However, thanks for reminding me, for consistency i would have to look into it too

@Alekcvp
Copy link
Author

Alekcvp commented Jun 23, 2017

Used by me ATM (removed double copy Data -> RBS -> Bytes):

function TSQLResultHelper.GetAsBytes(Index: Integer): TBytes;
var
  ASQLCode: SmallInt;
  BlobData: PBlobData;
begin
  CheckRange(Index);
  with Data.sqlvar[Index] do begin
    ASQLCode := SqlType and not(1);
    if SqlScale < 0 then
      raise EUIBConvertError.Create(EUIB_UNEXPECTEDERROR);
    case ASQLCode of
      SQL_TEXT:
        begin
          SetLength(Result, SqlLen);
          Move(SqlData^, Result[0], SqlLen);
        end;
      SQL_VARYING:
        begin
          SetLength(Result, PVary(SqlData).vary_length);
          Move(PVary(SqlData).vary_string[0], Result[0], PVary(SqlData).vary_length);
        end;
      SQL_BLOB:
        begin
          if not FetchBlobs then
            raise Exception.Create(EUIB_FETCHBLOBNOTSET);
          BlobData := GetDataQuadOffset(Index);
          SetLength(Result, BlobData.Size);
          Move(BlobData.Buffer^, Result[0], BlobData.Size);
        end;
    else
      raise EUIBConvertError.Create(EUIB_CASTERROR);
    end;
  end;
end;

@the-Arioch
Copy link
Owner

i just don't want to have a special case there for only char/varchar/blob

could have make some sense, if you would enforce "raw binary" condition: only OCTET for strings, only BINARY for blobs. But you do not.

Also, what about connection charset? if lc_type=NONE - then ALL string fields or blobs are de facto binary in this session, even if they are textual in the database. So, checking for "only raw binary fields/blobs" becomign yet more complex and fragile.

Thus, all types to be supported, to implement it properly.

@the-Arioch
Copy link
Owner

the problem with RawByteString is not that EMBT may deprecate it, buut rather that Henri still takes it as human-readable text and fills it with functions like FormatFloat

not that with Delphi insanity about "assignment-compatible types" he could do any different.
https://stackoverflow.com/questions/11029353 and others
one can use RawByteString or TFileName as any other non-special string

however for TBytes it realyl should be different, really shuld be just a dumb bytes dump

i'd use TValue, but what about older Delphi? :-)
However i only have xe2 and 10.1 and Lazarus, no matter how much time i invest, i would not be able to test it on d5 or d7

@Alekcvp
Copy link
Author

Alekcvp commented Jun 24, 2017

D5 и d7 ничего не знают ни про TValue, ни про TBytes, ни про RawByteString, так что их можно спокойно игнорировать IFDEFами (вместо всего этого там используется просто string, он же AnsiString в XE+).

А по поводу RawByteString из справки EMBT:

The purpose of RawByteString is to reduce the need for multiple overloads of procedures that read string data. This means that parameters of routines that process strings without regard for the string's code page should typically be of type RawByteString.
RawByteString should only be used as a parameter type, and only in routines which otherwise would need multiple overloads for AnsiStrings with different codepages.

Т.е. в UIB вместо RawByteString должна была быть AnsiAstring, т.к. конструкция вида RawByteString(DatTimeToString(...)) и AnsiString(DatTimeToString(...)) создают абсолютно одинаковый код:
arstring

И RawByteString там не нужен чуть более чем полностью. ИМХО.

@the-Arioch
Copy link
Owner

the-Arioch commented Jun 24, 2017

TBytes казалось бы давно была, даже раньше всяких TByteDynArray :-)

Разница именно в кодировках, в передаче таких переменных на вход функциям, принимающих Wide- UnicodeString. Потому rawBYTEstream, да.

У TBytes и прочих дин-массивов есть одна особенность, отсутствие COW-семантики.
Т.е. они более низкоуровневы, чем строки. Можно писать слегкa более быстрый код, но можно и сильно нарваться на изменение чужих переменных.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants