unit ABSConverts;

interface

{$I ABSVer.inc}

uses SysUtils, {Controls,} DB, Windows,
     ABSTypes,
     ABSStrUtils,
     ABSExcept,
     ABSConst;

const
  WildCardMultipleChar = '%';
  WildCardSingleChar = '_';

type
  TSQLFieldType = packed record
    SqlName: string;
    AdvancedFieldType: TABSAdvancedFieldType;
    BaseFieldType: TABSBaseFieldType;
    FieldType: TFieldType;
  end;
const
  SQLFieldTypes: array[1..62] of TSQLFieldType = (

    (SqlName: 'CHAR';           AdvancedFieldType: aftChar;           BaseFieldType: bftChar;         FieldType: ftFixedChar),
    (SqlName: 'FIXEDCHAR';      AdvancedFieldType: aftChar;           BaseFieldType: bftChar;         FieldType: ftFixedChar),
    (SqlName: 'STRING';         AdvancedFieldType: aftString;         BaseFieldType: bftVarchar;      FieldType: ftString),
    (SqlName: 'VARCHAR';        AdvancedFieldType: aftString;         BaseFieldType: bftVarchar;      FieldType: ftString),
    (SqlName: 'VARCHAR2';       AdvancedFieldType: aftString;         BaseFieldType: bftVarchar;      FieldType: ftString),
    (SqlName: 'WIDECHAR';       AdvancedFieldType: aftWideChar;       BaseFieldType: bftWideChar;     FieldType: ftWideString),
    (SqlName: 'FIXEDWIDECHAR';  AdvancedFieldType: aftWideChar;       BaseFieldType: bftWideChar;     FieldType: ftWideString),
    (SqlName: 'WIDESTRING';     AdvancedFieldType: aftWideString;     BaseFieldType: bftWideVarchar;  FieldType: ftWideString),
    (SqlName: 'WIDEVARCHAR';    AdvancedFieldType: aftWideString;     BaseFieldType: bftWideVarchar;  FieldType: ftWideString),

    (SqlName: 'SMALLINT';       AdvancedFieldType: aftSmallint;       BaseFieldType: bftSignedInt16;  FieldType: ftSmallint),
    (SqlName: 'SIGNEDINT16';    AdvancedFieldType: aftSmallint;       BaseFieldType: bftSignedInt16;  FieldType: ftSmallint),
    (SqlName: 'SHORTINT';       AdvancedFieldType: aftShortint;       BaseFieldType: bftSignedInt8;   FieldType: ftSmallint),
    (SqlName: 'SIGNEDINT8';     AdvancedFieldType: aftShortint;       BaseFieldType: bftSignedInt8;   FieldType: ftSmallint),
    (SqlName: 'INTEGER';        AdvancedFieldType: aftInteger;        BaseFieldType: bftSignedInt32;  FieldType: ftInteger),
    (SqlName: 'SIGNEDINT32';    AdvancedFieldType: aftInteger;        BaseFieldType: bftSignedInt32;  FieldType: ftInteger),
    (SqlName: 'LARGEINT';       AdvancedFieldType: aftLargeint;       BaseFieldType: bftSignedInt64;  FieldType: ftLargeint),
    (SqlName: 'INT64';          AdvancedFieldType: aftLargeint;       BaseFieldType: bftSignedInt64;  FieldType: ftLargeint),
    (SqlName: 'SIGNEDINT64';    AdvancedFieldType: aftLargeint;       BaseFieldType: bftSignedInt64;  FieldType: ftLargeint),
    (SqlName: 'WORD';           AdvancedFieldType: aftWord;           BaseFieldType: bftUnsignedInt16;FieldType: ftWord),
    (SqlName: 'UNSIGNEDINT16';  AdvancedFieldType: aftWord;           BaseFieldType: bftUnsignedInt16;FieldType: ftWord),
    (SqlName: 'BYTE';           AdvancedFieldType: aftByte;           BaseFieldType: bftUnsignedInt8; FieldType: ftWord),
    (SqlName: 'UNSIGNEDINT8';   AdvancedFieldType: aftByte;           BaseFieldType: bftUnsignedInt8; FieldType: ftWord),
    (SqlName: 'CARDINAL';       AdvancedFieldType: aftCardinal;       BaseFieldType: bftUnsignedInt32;FieldType: ftLargeint),
    (SqlName: 'UNSIGNEDINT32';  AdvancedFieldType: aftCardinal;       BaseFieldType: bftUnsignedInt32;FieldType: ftLargeint),

    (SqlName: 'AUTOINC';        AdvancedFieldType: aftAutoInc;        BaseFieldType: bftSignedInt32;  FieldType: ftAutoInc),
    (SqlName: 'AUTOINCSHORTINT';AdvancedFieldType: aftAutoIncShortint;BaseFieldType: bftSignedInt8;   FieldType: ftAutoInc),
    (SqlName: 'AUTOINCSMALLINT';AdvancedFieldType: aftAutoIncSmallint;BaseFieldType: bftSignedInt16;  FieldType: ftAutoInc),
    (SqlName: 'AUTOINCINTEGER'; AdvancedFieldType: aftAutoIncInteger; BaseFieldType: bftSignedInt32;  FieldType: ftAutoInc),
    (SqlName: 'AUTOINCLARGEINT';AdvancedFieldType: aftAutoIncLargeint;BaseFieldType: bftSignedInt64;  FieldType: ftLargeint),
    (SqlName: 'AUTOINCBYTE';    AdvancedFieldType: aftAutoIncByte;    BaseFieldType: bftUnsignedInt8; FieldType: ftAutoInc),
    (SqlName: 'AUTOINCWORD';    AdvancedFieldType: aftAutoIncWord;    BaseFieldType: bftUnsignedInt16;FieldType: ftAutoInc),
    (SqlName: 'AUTOINCCARDINAL';AdvancedFieldType: aftAutoIncCardinal;BaseFieldType: bftUnsignedInt32;FieldType: ftAutoInc),

    (SqlName: 'FLOAT';          AdvancedFieldType: aftDouble;         BaseFieldType: bftDouble;       FieldType: ftFloat),
    (SqlName: 'FLOAT';          AdvancedFieldType: aftDouble;         BaseFieldType: bftDouble;       FieldType: ftBCD),
    (SqlName: 'SINGLE';         AdvancedFieldType: aftSingle;         BaseFieldType: bftSingle;       FieldType: ftFloat),
    (SqlName: 'DOUBLE';         AdvancedFieldType: aftDouble;         BaseFieldType: bftDouble;       FieldType: ftFloat),
    (SqlName: 'EXTENDED';       AdvancedFieldType: aftExtended;       BaseFieldType: bftExtended;     FieldType: ftFloat),

    (SqlName: 'LOGICAL';        AdvancedFieldType: aftBoolean;        BaseFieldType: bftLogical;      FieldType: ftBoolean),
    (SqlName: 'BOOLEAN';        AdvancedFieldType: aftBoolean;        BaseFieldType: bftLogical;      FieldType: ftBoolean),
    (SqlName: 'BOOL';           AdvancedFieldType: aftBoolean;        BaseFieldType: bftLogical;      FieldType: ftBoolean),
    (SqlName: 'BIT';            AdvancedFieldType: aftBoolean;        BaseFieldType: bftLogical;      FieldType: ftBoolean),

    (SqlName: 'CURRENCY';        AdvancedFieldType: aftCurrency;      BaseFieldType: bftCurrency;     FieldType: ftCurrency),
    (SqlName: 'MONEY';          AdvancedFieldType: aftCurrency;      BaseFieldType: bftCurrency;     FieldType: ftCurrency),

    (SqlName: 'DATE';            AdvancedFieldType: aftDate;          BaseFieldType: bftDate;         FieldType: ftDate),
    (SqlName: 'TIME';            AdvancedFieldType: aftTime;          BaseFieldType: bftTime;         FieldType: ftTime),
    (SqlName: 'DATETIME';        AdvancedFieldType: aftDateTime;      BaseFieldType: bftDateTime;     FieldType: ftDateTime),
{$IFDEF D6H}
    (SqlName: 'TIMESTAMP';       AdvancedFieldType: aftTimeStamp;     BaseFieldType: bftDateTime;     FieldType: ftTimeStamp),
{$ELSE}
    (SqlName: 'TIMESTAMP';       AdvancedFieldType: aftTimeStamp;     BaseFieldType: bftDateTime;     FieldType: ftUnknown),
{$ENDIF}

    (SqlName: 'BYTES';           AdvancedFieldType: aftBytes;         BaseFieldType: bftBytes;        FieldType: ftBytes),
    (SqlName: 'VARBYTES';        AdvancedFieldType: aftVarBytes;      BaseFieldType: bftVarBytes;     FieldType: ftVarBytes),

    (SqlName: 'BLOB';            AdvancedFieldType: aftBlob;          BaseFieldType: bftBlob;         FieldType: ftBlob),
    (SqlName: 'BLOB';            AdvancedFieldType: aftBlob;          BaseFieldType: bftBlob;         FieldType: ftParadoxOle),
    (SqlName: 'BLOB';            AdvancedFieldType: aftBlob;          BaseFieldType: bftBlob;         FieldType: ftTypedBinary),
    (SqlName: 'BLOB';            AdvancedFieldType: aftBlob;          BaseFieldType: bftBlob;         FieldType: ftDBaseOle),
{$IFDEF D5H}
    (SqlName: 'BLOB';            AdvancedFieldType: aftBlob;          BaseFieldType: bftBlob;         FieldType: ftOraBlob),
    (SqlName: 'BLOB';            AdvancedFieldType: aftBlob;          BaseFieldType: bftBlob;         FieldType: ftOraClob),
{$ELSE}
    (SqlName: 'BLOB';            AdvancedFieldType: aftBlob;          BaseFieldType: bftBlob;         FieldType: ftUnknown),
    (SqlName: 'BLOB';            AdvancedFieldType: aftBlob;          BaseFieldType: bftBlob;         FieldType: ftUnknown),
{$ENDIF}
    (SqlName: 'GRAPHIC';         AdvancedFieldType: aftGraphic;       BaseFieldType: bftBlob;         FieldType: ftGraphic),
    (SqlName: 'MEMO';            AdvancedFieldType: aftMemo;          BaseFieldType: bftClob;         FieldType: ftMemo),
    (SqlName: 'CLOB';            AdvancedFieldType: aftMemo;          BaseFieldType: bftClob;         FieldType: ftMemo),
    (SqlName: 'FORMATTEDMEMO';   AdvancedFieldType: aftFormattedMemo; BaseFieldType: bftClob;         FieldType: ftFmtMemo),
{$IFDEF D10H}
    (SqlName: 'WIDEMEMO';        AdvancedFieldType: aftWideMemo;      BaseFieldType: bftWideClob;     FieldType: ftWideMemo),
    (SqlName: 'WIDECLOB';        AdvancedFieldType: aftWideMemo;      BaseFieldType: bftWideClob;     FieldType: ftWideMemo),
{$ELSE}
    (SqlName: 'WIDEMEMO';        AdvancedFieldType: aftWideMemo;      BaseFieldType: bftWideClob;     FieldType: ftBlob),
    (SqlName: 'WIDECLOB';        AdvancedFieldType: aftWideMemo;      BaseFieldType: bftWideClob;     FieldType: ftBlob),
{$ENDIF}
//    (SqlName: 'WIDEMEMO';        AdvancedFieldType: aftWideMemo;      BaseFieldType: bftWideClob;     FieldType: ftBlob),
{$IFDEF D5H}
    (SqlName: 'GUID';            AdvancedFieldType: aftGuid;          BaseFieldType: bftChar;         FieldType: ftGuid)
{$ELSE}
    (SqlName: 'GUID';            AdvancedFieldType: aftGuid;          BaseFieldType: bftChar;         FieldType: ftUnknown)
{$ENDIF}
  );

  // Convert AdvancedFieldType to BasicFieldType
  function AdvancedFieldTypeToBaseFieldType(AdvancedFieldType: TABSAdvancedFieldType): TABSBaseFieldType;
  // Convert BaseFieldType to AdvancedFieldType
  function BaseFieldTypeToAdvancedFieldType(BaseFieldType: TABSBaseFieldType): TABSAdvancedFieldType;

  // Converts TFieldType to TABSAdvancedFieldType
  function FieldTypeToABSAdvFieldType(FieldType: TFieldType): TABSAdvancedFieldType;
  // Converts TABSAdvancedFieldType to TFieldType
  function ABSAdvFieldTypeToFieldType(AdvancedFieldType: TABSAdvancedFieldType): TFieldType;

  // AdvancedFieldType for print
  function AftToStr(AdvancedFieldType: TABSAdvancedFieldType): string;
  // TypeName to TABSAdvancedFieldType
  function StrToAft(TypeName: string): TABSAdvancedFieldType;
  // BaseFieldType for print
  function BftToStr(BaseFieldType: TABSBaseFieldType): string;
  // FieldType for print
  function FtToStr(FieldType: TFieldType): string;


  // Convert ABSDate to Date
  function ABSDateToDate(ABSDate: TABSDate): TDateTime; overload;
  // Convert Date to ABSDate
  function DateToABSDate(Date: TDateTime): TABSDate; overload;

  // Convert ABSTime to Time
  function ABSTimeToTime(ABSTime: TABSTime): TDateTime; overload;
  // Convert Time to ABSTime
  function TimeToABSTime(Time: TDateTime): TABSTime; overload;

  // Convert ABSDateTime to DateTime
  function ABSDateTimeToDateTime(ABSDateTime: TABSDateTime): TDateTime; overload;
  // Convert DateTime to ABSDateTime
  function DateTimeToABSDateTime(DateTime: TDateTime): TABSDateTime; overload;

  // return true if field type is a BLOB field type
  function IsBLOBFieldType(FieldType: TABSBaseFieldType): Boolean; overload;
  function IsBLOBFieldType(FieldType: TABSAdvancedFieldType): Boolean; overload;

  // return true if field type is a string field type, but not wide string
  function IsStringFieldType(FieldType: TABSBaseFieldType): Boolean; overload;
  function IsStringFieldType(FieldType: TABSAdvancedFieldType): Boolean; overload;

  // return true if field type is a wide string field type
  function IsWideStringFieldType(FieldType: TABSBaseFieldType): Boolean; overload;
  function IsWideStringFieldType(FieldType: TABSAdvancedFieldType): Boolean; overload;

  // return true if field type is bytes field type
  function IsBytesFieldType(FieldType: TABSBaseFieldType): Boolean; overload;
  function IsBytesFieldType(FieldType: TABSAdvancedFieldType): Boolean; overload;

  // return true if field type is Autoinc field type
  function IsAutoincFieldType(FieldType: TABSAdvancedFieldType): Boolean; overload;

  // return true if DataType is numeric
  function IsNumericFieldType(FieldType: TABSBaseFieldType): Boolean; overload;
  function IsNumericFieldType(FieldType: TABSAdvancedFieldType): Boolean; overload;

  // return true if DataType is TateTime, Time, Date, TimeStamp
  function IsDateTimeFieldType(FieldType: TABSBaseFieldType): Boolean; overload;
  function IsDateTimeFieldType(FieldType: TABSAdvancedFieldType): Boolean; overload;

  // return true if DataType is String, bytes, etc.
  function IsSizebleFieldType(FieldType: TABSAdvancedFieldType): Boolean;

  // Result = Can cast this type
  function IsConvertableFieldType(FieldType: TABSAdvancedFieldType): boolean;

  // Like '%_' compare for String
  function IsStrMatchPattern(StrPtr: PAnsiChar; PatternPtr: PAnsiChar; IsPatternEscaped: Boolean; EscapeChar: AnsiChar; bIgnoreCase:boolean): Boolean;
  // Like '%_' compare for WideString
  function IsWideStrMatchPattern(StrPtr: PWideChar; PatternPtr: PWideChar; IsPatternEscaped: Boolean; EscapeChar: WideChar; bIgnoreCase:boolean): Boolean;

  // SrcField.Value := DestField.Value
  procedure AssignField(SrcField, DestField: TField);

  // 'YYYY-MM-DD' => TDate
  function ISODateStrToDate(const DateStr: string; var Date: TDateTime): Boolean;
  // 'HH:MM:SS' => TTime
  function ISOTimeStrToTime(const TimeStr: string; var Time: TDateTime): Boolean;
  // 'YYYY-MM-DD HH:MM:SS' => TDateTime
  function ISOTimeStampStrToDateTime(const TimeStampStr: string; var DateTime: TDateTime): Boolean;

implementation

uses
{$IFDEF D6H}DateUtils,{$ELSE}ABSD4Routines,{$ENDIF}
Classes;

//------------------------------------------------------------------------------
// Convert AdvancedFieldType to BasicFieldType
//------------------------------------------------------------------------------
function AdvancedFieldTypeToBaseFieldType(AdvancedFieldType: TABSAdvancedFieldType): TABSBaseFieldType;
var i: Integer;
begin
  Result := bftUnknown;
  for i:=Low(SQLFieldTypes) to High(SQLFieldTypes) do
    if SQLFieldTypes[i].AdvancedFieldType = AdvancedFieldType then
      begin
        Result := SQLFieldTypes[i].BaseFieldType;
        break;
      end;
end;//AdvancedFieldTypeToBasicFieldType


//------------------------------------------------------------------------------
// Convert BaseFieldType to AdvancedFieldType
//------------------------------------------------------------------------------
function BaseFieldTypeToAdvancedFieldType(BaseFieldType: TABSBaseFieldType): TABSAdvancedFieldType;
var i: Integer;
begin
  Result := aftUnknown;
  for i:=Low(SQLFieldTypes) to High(SQLFieldTypes) do
    if SQLFieldTypes[i].BaseFieldType = BaseFieldType then
      begin
        Result := SQLFieldTypes[i].AdvancedFieldType;
        break;
      end;
end;//BaseFieldTypeToAdvancedFieldType


//------------------------------------------------------------------------------
// Converts TFieldType to TABSAdvancedFieldType
//------------------------------------------------------------------------------
function FieldTypeToABSAdvFieldType(FieldType: TFieldType): TABSAdvancedFieldType;
var i: Integer;
begin
  Result := aftUnknown;
  for i:=Low(SQLFieldTypes) to High(SQLFieldTypes) do
    if SQLFieldTypes[i].FieldType = FieldType then
      begin
        Result := SQLFieldTypes[i].AdvancedFieldType;
        break;
      end;
  if (Result = aftUnknown) then
    raise EABSException.Create(30289, ErrorGUnknownDataType,
                               [IntToStr(Integer(FieldType))]); 
end;//FieldTypeToABSAdvFieldType


//------------------------------------------------------------------------------
// Converts TABSAdvancedFieldType to TFieldType
//------------------------------------------------------------------------------
function ABSAdvFieldTypeToFieldType(AdvancedFieldType: TABSAdvancedFieldType): TFieldType;
var i: Integer;
begin
  Result := ftUnknown;
  for i:=Low(SQLFieldTypes) to High(SQLFieldTypes) do
    if SQLFieldTypes[i].AdvancedFieldType = AdvancedFieldType then
      begin
        Result := SQLFieldTypes[i].FieldType;
        break;
      end;
end;//ABSAdvFieldTypeToFieldType


//------------------------------------------------------------------------------
// AdvancedFieldType for print
//------------------------------------------------------------------------------
function AftToStr(AdvancedFieldType: TABSAdvancedFieldType): string;
var i: Integer;
begin
  Result := 'Unknown';
  for i:=Low(SQLFieldTypes) to High(SQLFieldTypes) do
    if SQLFieldTypes[i].AdvancedFieldType = AdvancedFieldType then
      begin
        Result := SQLFieldTypes[i].SqlName;
        break;
      end;
end;//AftToStr


//------------------------------------------------------------------------------
// TypeName to TABSAdvancedFieldType
//------------------------------------------------------------------------------
function StrToAft(TypeName: string): TABSAdvancedFieldType;
var
 i: Integer;
 u: string;
begin
  Result := aftUnknown;
  u := UpperCase(TypeName);
  for i:=Low(SQLFieldTypes) to High(SQLFieldTypes) do
   if ( UpperCase(SQLFieldTypes[i].SqlName) = u ) then
    begin
     Result := SQLFieldTypes[i].AdvancedFieldType;
     Break;
    end;
end;//StrToAft


//------------------------------------------------------------------------------
// BaseFieldType for print
//------------------------------------------------------------------------------
function BftToStr(BaseFieldType: TABSBaseFieldType): string;
var i: Integer;
begin
  Result := 'Unknown';
  for i:=Low(SQLFieldTypes) to High(SQLFieldTypes) do
    if SQLFieldTypes[i].BaseFieldType = BaseFieldType then
      begin
        Result := SQLFieldTypes[i].SqlName;
        break;
      end;
end;//BftToStr


//------------------------------------------------------------------------------
// FieldType for print
//------------------------------------------------------------------------------
function FtToStr(FieldType: TFieldType): string;
var i: Integer;
begin
  Result := 'Unknown';
  for i:=Low(SQLFieldTypes) to High(SQLFieldTypes) do
    if SQLFieldTypes[i].FieldType = FieldType then
      begin
        Result := SQLFieldTypes[i].SqlName;
        break;
      end;
end;//FtToStr


//------------------------------------------------------------------------------
// Convert ABSDate to Date
//------------------------------------------------------------------------------
function ABSDateToDate(ABSDate: TABSDate): TDateTime;
const
  // MinInteger (-2147483648) + DateDelta
  MinDate = -2146790054;
begin

  if ABSDate > MinDate then
   Result := ABSDate - DateDelta;
end;//ABSDateToDate


//------------------------------------------------------------------------------
// Convert Date to ABSDate
//------------------------------------------------------------------------------
function DateToABSDate(Date: TDateTime): TABSDate;
begin
  Result := Trunc(Date) + DateDelta;
end;//DateToABSDate


//------------------------------------------------------------------------------
// Convert ABSTime to Time
//------------------------------------------------------------------------------
function ABSTimeToTime(ABSTime: TABSTime): TDateTime;
begin
  Result := Frac(ABSTime / (24*60*60*1000));
end;//ABSTimeToTime


//------------------------------------------------------------------------------
// Convert Time to ABSTime
//------------------------------------------------------------------------------
function TimeToABSTime(Time: TDateTime): TABSTime;
begin
  //Result := Trunc(Frac(Time) * (24*60*60*1000));
  Result := Round(Frac(Time) * (24*60*60*1000));
end;//TimeToABSTime


//------------------------------------------------------------------------------
// Convert ABSDateTime to DateTime
//------------------------------------------------------------------------------
function ABSDateTimeToDateTime(ABSDateTime: TABSDateTime): TDateTime;
begin
  Result := ABSDateToDate(ABSDateTime.Date) + ABSTimeToTime(ABSDateTime.Time);
end;//ABSDateTimeToDateTime


//------------------------------------------------------------------------------
// Convert DateTime to ABSDateTime
//------------------------------------------------------------------------------
function DateTimeToABSDateTime(DateTime: TDateTime): TABSDateTime;
begin
  Result.Date := DateToABSDate(DateTime);
  Result.Time := TimeToABSTime(DateTime);
end;//ABSDateTimeToDateTime


//------------------------------------------------------------------------------
// return true if field type is a BLOB field type
//------------------------------------------------------------------------------
function IsBLOBFieldType(FieldType: TABSBaseFieldType): Boolean;
begin
  Result := FieldType in [bftBLOB, bftClob, bftWideClob];
end; // IsBLOBFieldType


//------------------------------------------------------------------------------
// return true if field type is a BLOB field type
//------------------------------------------------------------------------------
function IsBLOBFieldType(FieldType: TABSAdvancedFieldType): Boolean;
begin
  Result := FieldType in [aftBLOB, aftGraphic, aftMemo, aftFormattedMemo, aftWideMemo];
end; // IsBLOBFieldType


//------------------------------------------------------------------------------
// return true if field type is a string field type, but not wide string
//------------------------------------------------------------------------------
function IsStringFieldType(FieldType: TABSBaseFieldType): Boolean;
begin
  Result := FieldType in [bftChar, bftWideChar, bftVarchar, bftWideVarchar];
end; // IsStringFieldType


//------------------------------------------------------------------------------
// return true if field type is a string field type, but not wide string
//------------------------------------------------------------------------------
function IsStringFieldType(FieldType: TABSAdvancedFieldType): Boolean;
begin
  Result := FieldType in [aftChar, aftString, aftWideChar, aftWideString, aftGuid];
end; // IsStringFieldType


//------------------------------------------------------------------------------
// return true if field type is a wide string field type
//------------------------------------------------------------------------------
function IsWideStringFieldType(FieldType: TABSBaseFieldType): Boolean;
begin
  Result := FieldType in [bftWideChar, bftWideVarchar];
end; // IsStringFieldType


//------------------------------------------------------------------------------
// return true if field type is a wide string field type
//------------------------------------------------------------------------------
function IsWideStringFieldType(FieldType: TABSAdvancedFieldType): Boolean;
begin
  Result := FieldType in [aftWideChar, aftWideString];
end; // IsWideStringFieldType


//------------------------------------------------------------------------------
// return true if field type is a Bytes field type, but not wide Bytes
//------------------------------------------------------------------------------
function IsBytesFieldType(FieldType: TABSBaseFieldType): Boolean;
begin
  Result := FieldType in [bftBytes, bftVarBytes];
end; // IsBytesFieldType


//------------------------------------------------------------------------------
// return true if field type is a Bytes field type, but not wide Bytes
//------------------------------------------------------------------------------
function IsBytesFieldType(FieldType: TABSAdvancedFieldType): Boolean;
begin
  Result := FieldType in [aftBytes, aftVarBytes];
end; // IsBytesFieldType


//------------------------------------------------------------------------------
// return true if field type is a Autoinc field type, but not wide Autoinc
//------------------------------------------------------------------------------
function IsAutoincFieldType(FieldType: TABSAdvancedFieldType): Boolean;
begin
  Result := FieldType in [aftAutoInc,
                          aftAutoIncShortint,
                          aftAutoIncSmallint,
                          aftAutoIncInteger,
                          aftAutoIncLargeint,
                          aftAutoIncByte,
                          aftAutoIncWord,
                          aftAutoIncCardinal];
end; // IsAutoincFieldType


//------------------------------------------------------------------------------
// return true if DataType is numeric
//------------------------------------------------------------------------------
function IsNumericFieldType(FieldType: TABSBaseFieldType): Boolean;
begin
  Result := FieldType in [bftSignedInt8, bftSignedInt16, bftSignedInt32, bftSignedInt64,
                          bftUnsignedInt8, bftUnsignedInt16, bftUnsignedInt32,
                          bftSingle, bftDouble, bftExtended, bftCurrency];
end;//IsNumericDataType


//------------------------------------------------------------------------------
// return true if DataType is numeric
//------------------------------------------------------------------------------
function IsNumericFieldType(FieldType: TABSAdvancedFieldType): Boolean;
begin
  Result := IsNumericFieldType(AdvancedFieldTypeToBaseFieldType(FieldType));
end;//IsNumericDataType


//------------------------------------------------------------------------------
// return true if DataType is TateTime, Time, Date, TimeStamp
//------------------------------------------------------------------------------
function IsDateTimeFieldType(FieldType: TABSBaseFieldType): Boolean;
begin
  Result := FieldType in [bftDate, bftTime, bftDateTime];
end;//IsDateTimeFieldType


//------------------------------------------------------------------------------
// return true if DataType is TateTime, Time, Date, TimeStamp
//------------------------------------------------------------------------------
function IsDateTimeFieldType(FieldType: TABSAdvancedFieldType): Boolean;
begin
  Result := IsDateTimeFieldType(AdvancedFieldTypeToBaseFieldType(FieldType));
end;//IsDateTimeFieldType


//------------------------------------------------------------------------------
// return true if DataType is String, bytes, etc.
//------------------------------------------------------------------------------
function IsSizebleFieldType(FieldType: TABSAdvancedFieldType): Boolean;
begin
  Result := (IsStringFieldType(FieldType) or (FieldType in [aftBytes, aftVarBytes])) and
     (FieldType <> aftGuid); // 5.05 fix ExportToSQL problem
end;//IsSizebleFieldType


//------------------------------------------------------------------------------
// Result = Can cast this type
//------------------------------------------------------------------------------
function IsConvertableFieldType(FieldType: TABSAdvancedFieldType): boolean;
begin
  Result := FieldType in [aftChar, aftString, aftWideChar, aftWideString,
                          aftShortint, aftSmallint,
                          aftAutoInc,aftAutoIncShortint,aftAutoIncSmallint,aftAutoIncInteger,aftAutoIncLargeint,aftAutoIncByte,aftAutoIncWord,aftAutoIncCardinal,
                          aftInteger,
                          aftLargeint, aftByte, aftWord, aftCardinal,
                          aftSingle, aftDouble, aftExtended,
                          aftBoolean,
                          aftCurrency,
                          aftDate, aftTime, aftDateTime, aftTimeStamp,
                          aftMemo, aftFormattedMemo, aftWideMemo];
end; // IsConvertableFieldType


function IsStrMatchPattern(StrPtr: PAnsiChar; PatternPtr: PAnsiChar; IsPatternEscaped: Boolean; EscapeChar: AnsiChar; bIgnoreCase:boolean): Boolean;
var i : integer;
    bEQ: Boolean;
    tmp1, tmp2: array [0..1] of AnsiChar;
begin
  tmp1[0]:=#0; tmp1[1]:=#0;
  tmp2[0]:=#0;tmp2[1]:=#0;
  repeat
      if (StrComp(PatternPtr,WildCardMultipleChar)=0) then
       begin
         Result:=True;
         exit;
       end
      else if (StrPtr^=#0) and (PatternPtr^ <> #0) then
       begin
         Result:=False;
         exit;
       end
      else if (StrPtr^=#0) then
       begin
         Result:=True;
         exit;
       end
      else
         begin
           case PatternPtr^ of
            WildCardMultipleChar:
               begin
                for i:=0 to Length(StrPtr)-1 do
                 begin
                  if IsStrMatchPattern(StrPtr+i,PatternPtr+1,IsPatternEscaped,EscapeChar,bIgnoreCase) then
                   begin
                    Result := True;
                    exit;
                   end;
                 end;
                Result := False;
                exit;
               end;
            WildCardSingleChar:
               begin
                inc(StrPtr);
                inc(PatternPtr);
               end;
            else
               begin
                if (IsPatternEscaped and (PatternPtr^ = EscapeChar)) then
                  inc(PatternPtr);
                tmp1[0] := StrPtr^;
                tmp2[0] := PatternPtr^;
                if (bIgnoreCase) then
                 //bEQ := (Q_AnsiCompTextL(tmp1, tmp2, 1) = 0)
                 bEQ := (CompareStringA(LOCALE_USER_DEFAULT,
                         NORM_IGNORECASE + SORT_STRINGSORT,
                         tmp1, 1, tmp2, 1) - 2) = 0
                else
                 //bEQ := (Q_AnsiCompStrL(tmp1, tmp2, 1) = 0);
                 bEQ := (CompareStringA(LOCALE_USER_DEFAULT,
                         SORT_STRINGSORT,
                         tmp1, 1, tmp2, 1) - 2) = 0;
                if (bEQ) then
                 begin
                  inc(StrPtr);
                  inc(PatternPtr);
                 end
                else
                 begin
                  Result:=False;
                  exit;
                 end;
               end;
           end; // case
         end; // non-simple cases
  until false;
end;// IsStrMatchPattern

//------------------------------------------------------------------------------
// Like '%_' compare for WideString
//------------------------------------------------------------------------------
function IsWideStrMatchPattern(StrPtr: PWideChar; PatternPtr: PWideChar; IsPatternEscaped: Boolean; EscapeChar: WideChar; bIgnoreCase:boolean): Boolean;
var i: integer;
    bOk: boolean;
begin
  repeat
      if (CompareStringW(LOCALE_USER_DEFAULT,
                        NORM_IGNORECASE + SORT_STRINGSORT,
                        PatternPtr,
                        Length(PatternPtr),
                        WideChar(WildCardMultipleChar),
                        1)-2 = 0) then
       begin
         Result:=True;
         exit;
       end
      else if (StrPtr^=#0) and (PatternPtr^ <> #0) then
       begin
         Result:=False;
         exit;
       end
      else if (StrPtr^=#0) then
       begin
         Result:=True;
         exit;
       end
      else
         begin
           case PatternPtr^ of
            WildCardMultipleChar:
               begin
                for i:=0 to Length(StrPtr)-1 do
                 begin
                  if IsWideStrMatchPattern(StrPtr+i,PatternPtr+1,IsPatternEscaped,EscapeChar,bIgnoreCase) then
                   begin
                    Result := True;
                    exit;
                   end;
                 end;
                Result := False;
                exit;
               end;
            WildCardSingleChar:
               begin
                inc(StrPtr);
                inc(PatternPtr);
               end;
            else
               begin
                bOk := false;
                if (IsPatternEscaped and (PatternPtr^ = EscapeChar)) then
                  inc(PatternPtr);
                if bIgnoreCase then
                 begin
                  if (ABSStrUtils.CompareStringW(LOCALE_USER_DEFAULT,
                        NORM_IGNORECASE + SORT_STRINGSORT,
                        PatternPtr, 1, StrPtr,1)-2 = 0) then
                   bOk := true;
                 end
                else
                 begin
                  if (ABSStrUtils.CompareStringW(LOCALE_USER_DEFAULT,
                        SORT_STRINGSORT,
                        PatternPtr, 1, StrPtr,1)-2 = 0) then
                   bOk := true;
                 end;

                if (bOk) then
                 begin
                  inc(StrPtr);
                  inc(PatternPtr);
                 end
                else
                 begin
                  Result:=False;
                  exit;
                 end;
               end;
           end; // case
         end; // non-simple cases
  until false;
end;// IsWideStrMatchPattern


// DestField.Value := SrcField.Value
procedure AssignField(SrcField, DestField: TField);
var
  A: Variant;
  SrcBlobStream: TStream;
  DestBlobStream: TStream;
  Size: Longint;
  Header: TGraphicHeader;
  ws: WideString;
begin
  case SrcField.DataType of
    ftLargeint:
      if TLargeintField(SrcField).IsNull = True then
        TLargeintField(DestField).Clear
      else
        if (DestField is TLargeintField) then
          TLargeintField(DestField).AsLargeInt := TLargeintField(SrcField).AsLargeInt
        else
          DestField.Assign(SrcField);
    ftVarBytes:
      begin
        // 5.13 - fix ALTER TABLE problem
        if DestField.Value <> SrcField.Value then
        begin
          A := SrcField.Value;
          {$IFDEF D5H}
          DestField.SetData(@A, False);
          {$ELSE}
          DestField.SetData(@A);
          {$ENDIF}
        end;
      end;
{$IFDEF D10H}
    ftWideMemo:
          DestField.Value := SrcField.AsWideString;
{$ENDIF}
    else
      begin
        if (SrcField.IsBlob and DestField.IsBlob) then
{$IFDEF D10H}
        if (DestField.DataType = ftWideMemo) then
          DestField.AsWideString := SrcField.Value
        else
{$ENDIF}
          begin
            SrcBlobStream := SrcField.DataSet.CreateBlobStream(SrcField, bmRead);
            DestBlobStream := DestField.Dataset.CreateBlobStream(DestField, bmWrite);
            try
              Size := SrcBlobStream.Size;
              // check for Graphic Header
              if Size >= SizeOf(TGraphicHeader) then
              begin
                SrcBlobStream.Read(Header, SizeOf(Header));
                if (Header.Count <> 1) or (Header.HType <> $0100) or
                  (Header.Size <> Size - SizeOf(Header)) then
                  SrcBlobStream.Position := 0;
              end;
              DestBlobStream.CopyFrom(SrcBlobStream, SrcBlobStream.Size-SrcBlobStream.Position);
            finally
              SrcBlobStream.Free;
              DestBlobStream.Free;
            end;
          end
        else
          if ((SrcField.DataType = ftWideString) and DestField.IsBlob) then
            begin
              DestBlobStream := DestField.Dataset.CreateBlobStream(DestField, bmWrite);
              try
                ws := SrcField.Value;
                DestBlobStream.Write(PWideChar(ws)^, Length(ws)*sizeof(WideChar));
              finally
                DestBlobStream.Free;
              end;
            end
          else
            if ((DestField.DataType = ftWideString) and SrcField.IsBlob) then
              begin
                SrcBlobStream := SrcField.DataSet.CreateBlobStream(SrcField, bmRead);
                try
                  SetLength(ws, SrcBlobStream.Size div sizeof(WideChar));
                  SrcBlobStream.Read(PWideChar(ws)^, SrcBlobStream.Size);
                  DestField.Value := ws;
                finally
                  SrcBlobStream.Free;
                end;
              end
            else begin
              if (DestField is TLargeintField) and (not (SrcField is TLargeIntField)) then
                TLargeIntField(DestField).Value := SrcField.AsInteger
              else
                DestField.Assign(SrcField);
            end;
      end;
  end;
end;

function ExtractNumericPart(const DateTimeStr: string; DigitsCount: Integer; var Value: Word; var Pos: Integer): Boolean;
var
  s: string;
  count: Integer;
begin
  s := '';
  count := 0;
  while ((pos <= Length(DateTimeStr)) and not (AnsiChar(DateTimeStr[pos]) in ['-',' ',':'])) do
    begin
      if (DateTimeStr[pos] < '0') or (DateTimeStr[pos] > '9') then
        break;
      s := s + DateTimeStr[pos];
      Inc(pos);
      Inc(Count);
    end;
  Inc(pos);
  Result := (Count = DigitsCount);
  if Result then
    Value := StrToInt(s);
end;

// 'YYYY-MM-DD' => TDate
function ISODateStrToDate(const DateStr: string; var Date: TDateTime): Boolean;
var
  Year, Month, Day: Word;
  pos: Integer;
begin
{
<date value> ::=
    <years value> <minus sign> <months value>
        <minus sign> <days value>
}
  pos := 1;
  Result := ExtractNumericPart(DateStr,4,Year,Pos);
  if (Result) then
    Result := ExtractNumericPart(DateStr,2,Month,Pos);
  if (Result) then
    Result := ExtractNumericPart(DateStr,2,Day, Pos);
  if (Result) then
    Result := (Pos > Length(DateStr));
  if (Result) then
    Date := EncodeDate(Year,Month,Day);
end;


// 'HH:MM:SS' => TTime
function ISOTimeStrToTime(const TimeStr: string; var Time: TDateTime): Boolean;
var
  Hour,Min,Sec,MSec: Word;
  pos: Integer;
begin
  Pos := 1;
  MSec := 0;
  Result := ExtractNumericPart(TimeStr,2,Hour,Pos);
  if (Result) then
    Result := ExtractNumericPart(TimeStr,2,Min,Pos);
  if (Result) then
    Result := ExtractNumericPart(TimeStr,2,Sec,Pos);
  if (Result) then
    Result := (Pos > Length(TimeStr));
  if (Result) then
    Time := EncodeTime(Hour,Min,Sec,MSec);
end;


// 'YYYY-MM-DD HH:MM:SS' => TDateTime
function ISOTimeStampStrToDateTime(const TimeStampStr: string; var DateTime: TDateTime): Boolean;
var
  Year, Month, Day: Word;
  Hour,Min,Sec,MSec: Word;
  pos: Integer;
begin
  Pos := 1;
  MSec := 0;
  Result := ExtractNumericPart(TimeStampStr,4,Year,Pos);
  if (Result) then
    Result := ExtractNumericPart(TimeStampStr,2,Month,Pos);
  if (Result) then
    Result := ExtractNumericPart(TimeStampStr,2,Day,Pos);
  if (Result) then
    Result := ExtractNumericPart(TimeStampStr,2,Hour,Pos);
  if (Result) then
    Result := ExtractNumericPart(TimeStampStr,2,Min,Pos);
  if (Result) then
    Result := ExtractNumericPart(TimeStampStr,2,Sec,Pos);
  if (Result) then
    Result := (Pos > Length(TimeStampStr));
  if (Result) then
    DateTime := EncodeDateTime(Year,Month,Day, Hour,Min,Sec,MSec);
end;


end.
