
//////////////////////////////////////////////////
//  SQLite Data Access Components
//  Copyright © 2014 Devart. All right reserved.
//////////////////////////////////////////////////

{$IFNDEF CLR}
{$I LiteDac.inc}

unit LiteDataTypeMapUni;
{$ENDIF}

interface

uses
  SysUtils,
  DB,
  CRTypes, CRDataTypeMap, MemData;

const
  liteBase                  = 600;

  { native SQLite types }

  liteInteger               = liteBase + 1;
  liteReal                  = liteBase + 2;
  liteText                  = liteBase + 3;
  liteBlob                  = liteBase + 4;
  liteNull                  = liteBase + 5;

  { additional types handled by LiteDAC }

  liteTinyInt               = liteBase + 6;
  liteInt2                  = liteBase + 7;
  liteSmallInt              = liteBase + 8;
  liteInt                   = liteBase + 9;
  liteMediumInt             = liteBase + 10;
  liteBigInt                = liteBase + 11;
  liteUBigInt               = liteBase + 12;
  liteInt8                  = liteBase + 13;
  liteInt64                 = liteBase + 14;

  liteChar                  = liteBase + 15;
  liteVarChar               = liteBase + 16;
  liteClob                  = liteBase + 17;

  liteFloat                 = liteBase + 18;
  liteDouble                = liteBase + 19;
  liteNumeric               = liteBase + 20;
  liteDecimal               = liteBase + 21;
  liteNumber                = liteBase + 22;
  liteMoney                 = liteBase + 23;

  liteBool                  = liteBase + 24;

  liteBinary                = liteBase + 25;
  liteVarBinary             = liteBase + 26;

  liteDate                  = liteBase + 27;
  liteTime                  = liteBase + 28;
  liteDateTime              = liteBase + 29;
  liteTimestamp             = liteBase + 30;

type
  TLiteMapRules = class(TCRMapRules)
  public
    class function GetConverterManager: TConverterManager; override;
  end;

  TLiteConverterManager = class(TConverterManager)
  public
    constructor Create;

    class function GetDBProvider: Word; override;
    class function GetDBType(var SQLTypeName: string): Word; overload;
    class function GetDBType(SQLType: integer): Word; overload;
  end;

  TLiteDataConverters = class(TDataConverters)
  public
    class function RealToDateTime(StringHeap: TStringHeap; Source: IntPtr; SourceLen, SourceScale: Integer; Dest: IntPtr; DestLen, DestScale: Integer; IgnoreConvertErrors: Boolean): TConvertStatus; {$IFDEF CLR}static;{$ENDIF}
    class function DateTimeToReal(StringHeap: TStringHeap; Source: IntPtr; SourceLen, SourceScale: Integer; Dest: IntPtr; DestLen, DestScale: Integer; IgnoreConvertErrors: Boolean): TConvertStatus; {$IFDEF CLR}static;{$ENDIF}
    class function IntToDateTime(StringHeap: TStringHeap; Source: IntPtr; SourceLen, SourceScale: Integer; Dest: IntPtr; DestLen, DestScale: Integer; IgnoreConvertErrors: Boolean): TConvertStatus; {$IFDEF CLR}static;{$ENDIF}
    class function DateTimeToInt(StringHeap: TStringHeap; Source: IntPtr; SourceLen, SourceScale: Integer; Dest: IntPtr; DestLen, DestScale: Integer; IgnoreConvertErrors: Boolean): TConvertStatus; {$IFDEF CLR}static;{$ENDIF}
  end;

  procedure InitLiteTypes;

implementation

uses
  StrUtils,
{$IFNDEF CLR}
  CLRClasses,
{$ELSE}
  System.Runtime.InteropServices,
{$ENDIF}
  DateUtils,
{$IFNDEF UNIDACPRO}
  LiteCall, LiteClasses;
{$ELSE}
  LiteCallUni, LiteClassesUni;
{$ENDIF}

var
  LiteConverterManager: TLiteConverterManager;

procedure InitLiteTypes;
begin
  DBTypeInfos.Add(liteInteger,    'Integer',          False, False);
  DBTypeInfos.Add(liteReal,       'Real',             False, False);
  DBTypeInfos.Add(liteText,       'Text',             False, False);
  DBTypeInfos.Add(liteBlob,       'BLOB',             False, False);
  DBTypeInfos.Add(liteNull,       'Unknown',          False, False);

  DBTypeInfos.Add(liteTinyInt,    'TinyInt',          False, False);
  DBTypeInfos.Add(liteSmallInt,   'SmallInt',         False, False);
  DBTypeInfos.Add(liteInt2,       'Int2',             False, False);
  DBTypeInfos.Add(liteInt,        'Int',              False, False);
  DBTypeInfos.Add(liteMediumInt,  'MediumInt',        False, False);
  DBTypeInfos.Add(liteBigInt,     'BigInt',           False, False);
  DBTypeInfos.Add(liteUBigInt,    'Unsigned BigInt',  False, False);
  DBTypeInfos.Add(liteInt8,       'Int8',             False, False);
  DBTypeInfos.Add(liteInt64,      'Int64',            False, False);
  DBTypeInfos.Add(liteChar,       'Char',             True,  False);
  DBTypeInfos.Add(liteVarChar,    'VarChar',          True,  False);
  DBTypeInfos.Add(liteClob,       'CLOB',             False, False);
  DBTypeInfos.Add(liteFloat,      'Float',            False, False);
  DBTypeInfos.Add(liteDouble,     'Double',           False, False);
  DBTypeInfos.Add(liteNumeric,    'Numeric',          True,  True);
  DBTypeInfos.Add(liteDecimal,    'Decimal',          True,  True);
  DBTypeInfos.Add(liteNumber,     'Number',           True,  True);
  DBTypeInfos.Add(liteMoney,      'Money',            False, False);
  DBTypeInfos.Add(liteBool,       'Bool',             False, False);
  DBTypeInfos.Add(liteBinary,     'Binary',           True,  False);
  DBTypeInfos.Add(liteVarBinary,  'VarBinary',        True,  False);
  DBTypeInfos.Add(liteDate,       'Date',             False, False);
  DBTypeInfos.Add(liteTime,       'Time',             False, False);
  DBTypeInfos.Add(liteDateTime,   'DateTime',         False, False);
  DBTypeInfos.Add(liteTimestamp,  'Timestamp',        False, False);
end;

{ TLiteMapRules }

class function TLiteMapRules.GetConverterManager: TConverterManager;
begin
  Result := LiteConverterManager;
end;

{ TLiteConverterManager }

constructor TLiteConverterManager.Create;
begin
  inherited;

  AddFetchConverter(liteBlob, dtMemo);
  AddFetchConverter(liteBlob, dtWideMemo);
  AddFetchConverter(liteBlob, dtString,     dtMemo);
  AddFetchConverter(liteBlob, dtWideString, dtWideMemo);

  AddFetchConverter(liteClob, dtMemo);
  AddFetchConverter(liteClob, dtWideMemo);
  AddFetchConverter(liteClob, dtString,     dtMemo);
  AddFetchConverter(liteClob, dtWideString, dtWideMemo);

  AddFetchConverter(liteText, dtMemo);
  AddFetchConverter(liteText, dtWideMemo);
  AddFetchConverter(liteText, dtString,     dtMemo);
  AddFetchConverter(liteText, dtWideString, dtWideMemo);
  AddFetchConverter(liteText, dtUnknown);
  AddFetchConverter(liteText, dtBoolean);
  AddFetchConverter(liteText, dtInt8);
  AddFetchConverter(liteText, dtInt16);
  AddFetchConverter(liteText, dtUInt16);
  AddFetchConverter(liteText, dtInt32);
  AddFetchConverter(liteText, dtUInt32);
  AddFetchConverter(liteText, dtInt64);
  AddFetchConverter(liteText, dtBCD);
{$IFNDEF FPC}
  AddFetchConverter(liteText, dtFMTBCD);
{$ENDIF}
  AddFetchConverter(liteText, dtFloat);
  AddFetchConverter(liteText, dtCurrency);
  AddFetchConverter(liteText, dtDate);
  AddFetchConverter(liteText, dtTime);
  AddFetchConverter(liteText, dtDateTime);
  AddFetchConverter(liteText, dtBytes);
  AddFetchConverter(liteText, dtVarBytes);


  AddFetchConverter(liteInteger, -1, -1, -1, -1, dtInt8,     dtInt64);
  AddFetchConverter(liteInteger, -1, -1, -1, -1, dtInt16,    dtInt64);
  AddFetchConverter(liteInteger, -1, -1, -1, -1, dtUInt16,   dtInt64);
  AddFetchConverter(liteInteger, -1, -1, -1, -1, dtInt32,    dtInt64);
  AddFetchConverter(liteInteger, -1, -1, -1, -1, dtUInt32,   dtInt64);
  AddFetchConverter(liteInteger, -1, -1, -1, -1, dtInt64,    dtInt64);
  AddFetchConverter(liteInteger, -1, -1, -1, -1, dtFloat,    dtFloat);
  AddFetchConverter(liteInteger, -1, -1, -1, -1, dtCurrency, dtFloat);

  AddFetchConverter(liteTinyInt, -1, -1, -1, -1, dtInt8,   dtInt16);
  AddFetchConverter(liteTinyInt, -1, -1, -1, -1, dtInt16,  dtInt16);
  AddFetchConverter(liteTinyInt, -1, -1, -1, -1, dtUInt16, dtInt16);
  AddFetchConverter(liteTinyInt, -1, -1, -1, -1, dtInt32,  dtInt16);
  AddFetchConverter(liteTinyInt, -1, -1, -1, -1, dtUInt32, dtInt16);
  AddFetchConverter(liteTinyInt, -1, -1, -1, -1, dtInt64,  dtInt16);

  AddFetchConverter(liteSmallInt, -1, -1, -1, -1, dtInt8,   dtInt16);
  AddFetchConverter(liteSmallInt, -1, -1, -1, -1, dtInt16,  dtInt16);
  AddFetchConverter(liteSmallInt, -1, -1, -1, -1, dtUInt16, dtInt16);
  AddFetchConverter(liteSmallInt, -1, -1, -1, -1, dtInt32,  dtInt16);
  AddFetchConverter(liteSmallInt, -1, -1, -1, -1, dtUInt32, dtInt16);
  AddFetchConverter(liteSmallInt, -1, -1, -1, -1, dtInt64,  dtInt16);

  AddFetchConverter(liteInt2, -1, -1, -1, -1, dtInt8,   dtInt16);
  AddFetchConverter(liteInt2, -1, -1, -1, -1, dtInt16,  dtInt16);
  AddFetchConverter(liteInt2, -1, -1, -1, -1, dtUInt16, dtInt16);
  AddFetchConverter(liteInt2, -1, -1, -1, -1, dtInt32,  dtInt16);
  AddFetchConverter(liteInt2, -1, -1, -1, -1, dtUInt32, dtInt16);
  AddFetchConverter(liteInt2, -1, -1, -1, -1, dtInt64,  dtInt16);

  AddFetchConverter(liteInt, -1, -1, -1, -1, dtInt8,   dtInt32);
  AddFetchConverter(liteInt, -1, -1, -1, -1, dtInt16,  dtInt32);
  AddFetchConverter(liteInt, -1, -1, -1, -1, dtUInt16, dtInt32);
  AddFetchConverter(liteInt, -1, -1, -1, -1, dtInt32,  dtInt32);
  AddFetchConverter(liteInt, -1, -1, -1, -1, dtUInt32, dtInt32);
  AddFetchConverter(liteInt, -1, -1, -1, -1, dtInt64,  dtInt32);

  AddFetchConverter(liteMediumInt, -1, -1, -1, -1, dtInt8,   dtInt32);
  AddFetchConverter(liteMediumInt, -1, -1, -1, -1, dtInt16,  dtInt32);
  AddFetchConverter(liteMediumInt, -1, -1, -1, -1, dtUInt16, dtInt32);
  AddFetchConverter(liteMediumInt, -1, -1, -1, -1, dtInt32,  dtInt32);
  AddFetchConverter(liteMediumInt, -1, -1, -1, -1, dtUInt32, dtInt32);
  AddFetchConverter(liteMediumInt, -1, -1, -1, -1, dtInt64,  dtInt32);

  AddFetchConverter(liteBigInt, -1, -1, -1, -1, dtInt8,     dtInt64);
  AddFetchConverter(liteBigInt, -1, -1, -1, -1, dtInt16,    dtInt64);
  AddFetchConverter(liteBigInt, -1, -1, -1, -1, dtUInt16,   dtInt64);
  AddFetchConverter(liteBigInt, -1, -1, -1, -1, dtInt32,    dtInt64);
  AddFetchConverter(liteBigInt, -1, -1, -1, -1, dtUInt32,   dtInt64);
  AddFetchConverter(liteBigInt, -1, -1, -1, -1, dtInt64,    dtInt64);
  AddFetchConverter(liteBigInt, -1, -1, -1, -1, dtFloat,    dtFloat);
  AddFetchConverter(liteBigInt, -1, -1, -1, -1, dtCurrency, dtFloat);

  AddFetchConverter(liteUBigInt, -1, -1, -1, -1, dtInt8,     dtInt64);
  AddFetchConverter(liteUBigInt, -1, -1, -1, -1, dtInt16,    dtInt64);
  AddFetchConverter(liteUBigInt, -1, -1, -1, -1, dtUInt16,   dtInt64);
  AddFetchConverter(liteUBigInt, -1, -1, -1, -1, dtInt32,    dtInt64);
  AddFetchConverter(liteUBigInt, -1, -1, -1, -1, dtUInt32,   dtInt64);
  AddFetchConverter(liteUBigInt, -1, -1, -1, -1, dtInt64,    dtInt64);
  AddFetchConverter(liteUBigInt, -1, -1, -1, -1, dtFloat,    dtFloat);
  AddFetchConverter(liteUBigInt, -1, -1, -1, -1, dtCurrency, dtFloat);

  AddFetchConverter(liteInt8, -1, -1, -1, -1, dtInt8,   dtInt64);
  AddFetchConverter(liteInt8, -1, -1, -1, -1, dtInt16,  dtInt64);
  AddFetchConverter(liteInt8, -1, -1, -1, -1, dtUInt16, dtInt64);
  AddFetchConverter(liteInt8, -1, -1, -1, -1, dtInt32,  dtInt64);
  AddFetchConverter(liteInt8, -1, -1, -1, -1, dtUInt32, dtInt64);
  AddFetchConverter(liteInt8, -1, -1, -1, -1, dtInt64,  dtInt64);

  AddFetchConverter(liteInt64, -1, -1, -1, -1, dtInt8,     dtInt64);
  AddFetchConverter(liteInt64, -1, -1, -1, -1, dtInt16,    dtInt64);
  AddFetchConverter(liteInt64, -1, -1, -1, -1, dtUInt16,   dtInt64);
  AddFetchConverter(liteInt64, -1, -1, -1, -1, dtInt32,    dtInt64);
  AddFetchConverter(liteInt64, -1, -1, -1, -1, dtUInt32,   dtInt64);
  AddFetchConverter(liteInt64, -1, -1, -1, -1, dtInt64,    dtInt64);
  AddFetchConverter(liteInt64, -1, -1, -1, -1, dtFloat,    dtFloat);
  AddFetchConverter(liteInt64, -1, -1, -1, -1, dtCurrency, dtFloat);

  AddFetchConverter(liteNumeric,  1,  4, 0, 0, dtInt8,   dtInt16);
  AddFetchConverter(liteNumeric,  1,  4, 0, 0, dtInt16,  dtInt16);
  AddFetchConverter(liteNumeric,  1,  4, 0, 0, dtUInt16, dtInt16);
  AddFetchConverter(liteNumeric,  1,  4, 0, 0, dtInt32,  dtInt16);
  AddFetchConverter(liteNumeric,  1,  4, 0, 0, dtUInt32, dtInt16);
  AddFetchConverter(liteNumeric,  1,  4, 0, 0, dtInt64,  dtInt16);
  AddFetchConverter(liteNumeric,  5,  9, 0, 0, dtInt8,   dtInt32);
  AddFetchConverter(liteNumeric,  5,  9, 0, 0, dtInt16,  dtInt32);
  AddFetchConverter(liteNumeric,  5,  9, 0, 0, dtUInt16, dtInt32);
  AddFetchConverter(liteNumeric,  5,  9, 0, 0, dtInt32,  dtInt32);
  AddFetchConverter(liteNumeric,  5,  9, 0, 0, dtUInt32, dtInt32);
  AddFetchConverter(liteNumeric,  5,  9, 0, 0, dtInt64,  dtInt32);
  AddFetchConverter(liteNumeric, 10, -1, 0, 0, dtInt8,   dtInt64);
  AddFetchConverter(liteNumeric, 10, -1, 0, 0, dtInt16,  dtInt64);
  AddFetchConverter(liteNumeric, 10, -1, 0, 0, dtUInt16, dtInt64);
  AddFetchConverter(liteNumeric, 10, -1, 0, 0, dtInt32,  dtInt64);
  AddFetchConverter(liteNumeric, 10, -1, 0, 0, dtUInt32, dtInt64);
  AddFetchConverter(liteNumeric, 10, -1, 0, 0, dtInt64,  dtInt64);

  AddFetchConverter(liteNumeric, -1, -1,  1, -1, dtFloat);
  AddFetchConverter(liteNumeric, -1, -1,  1, -1, dtCurrency);
  AddFetchConverter(liteNumeric, -1, -1,  1, -1, dtBCD);
{$IFNDEF FPC}
  AddFetchConverter(liteNumeric, -1, -1,  1, -1, dtFmtBCD);
{$ENDIF}

  AddFetchConverter(liteDecimal,  1,  4, 0, 0, dtInt8,   dtInt16);
  AddFetchConverter(liteDecimal,  1,  4, 0, 0, dtInt16,  dtInt16);
  AddFetchConverter(liteDecimal,  1,  4, 0, 0, dtUInt16, dtInt16);
  AddFetchConverter(liteDecimal,  1,  4, 0, 0, dtInt32,  dtInt16);
  AddFetchConverter(liteDecimal,  1,  4, 0, 0, dtUInt32, dtInt16);
  AddFetchConverter(liteDecimal,  1,  4, 0, 0, dtInt64,  dtInt16);
  AddFetchConverter(liteDecimal,  5,  9, 0, 0, dtInt8,   dtInt32);
  AddFetchConverter(liteDecimal,  5,  9, 0, 0, dtInt16,  dtInt32);
  AddFetchConverter(liteDecimal,  5,  9, 0, 0, dtUInt16, dtInt32);
  AddFetchConverter(liteDecimal,  5,  9, 0, 0, dtInt32,  dtInt32);
  AddFetchConverter(liteDecimal,  5,  9, 0, 0, dtUInt32, dtInt32);
  AddFetchConverter(liteDecimal,  5,  9, 0, 0, dtInt64,  dtInt32);
  AddFetchConverter(liteDecimal, 10, -1, 0, 0, dtInt8,   dtInt64);
  AddFetchConverter(liteDecimal, 10, -1, 0, 0, dtInt16,  dtInt64);
  AddFetchConverter(liteDecimal, 10, -1, 0, 0, dtUInt16, dtInt64);
  AddFetchConverter(liteDecimal, 10, -1, 0, 0, dtInt32,  dtInt64);
  AddFetchConverter(liteDecimal, 10, -1, 0, 0, dtUInt32, dtInt64);
  AddFetchConverter(liteDecimal, 10, -1, 0, 0, dtInt64,  dtInt64);

  AddFetchConverter(liteDecimal, -1, -1,  1, -1, dtFloat);
  AddFetchConverter(liteDecimal, -1, -1,  1, -1, dtCurrency);
  AddFetchConverter(liteDecimal, -1, -1,  1, -1, dtBCD);
{$IFNDEF FPC}
  AddFetchConverter(liteDecimal, -1, -1,  1, -1, dtFmtBCD);
{$ENDIF}

  AddFetchConverter(liteNumber,  1,  4, 0, 0, dtInt8,   dtInt16);
  AddFetchConverter(liteNumber,  1,  4, 0, 0, dtInt16,  dtInt16);
  AddFetchConverter(liteNumber,  1,  4, 0, 0, dtUInt16, dtInt16);
  AddFetchConverter(liteNumber,  1,  4, 0, 0, dtInt32,  dtInt16);
  AddFetchConverter(liteNumber,  1,  4, 0, 0, dtUInt32, dtInt16);
  AddFetchConverter(liteNumber,  1,  4, 0, 0, dtInt64,  dtInt16);
  AddFetchConverter(liteNumber,  5,  9, 0, 0, dtInt8,   dtInt32);
  AddFetchConverter(liteNumber,  5,  9, 0, 0, dtInt16,  dtInt32);
  AddFetchConverter(liteNumber,  5,  9, 0, 0, dtUInt16, dtInt32);
  AddFetchConverter(liteNumber,  5,  9, 0, 0, dtInt32,  dtInt32);
  AddFetchConverter(liteNumber,  5,  9, 0, 0, dtUInt32, dtInt32);
  AddFetchConverter(liteNumber,  5,  9, 0, 0, dtInt64,  dtInt32);
  AddFetchConverter(liteNumber, 10, -1, 0, 0, dtInt8,   dtInt64);
  AddFetchConverter(liteNumber, 10, -1, 0, 0, dtInt16,  dtInt64);
  AddFetchConverter(liteNumber, 10, -1, 0, 0, dtUInt16, dtInt64);
  AddFetchConverter(liteNumber, 10, -1, 0, 0, dtInt32,  dtInt64);
  AddFetchConverter(liteNumber, 10, -1, 0, 0, dtUInt32, dtInt64);
  AddFetchConverter(liteNumber, 10, -1, 0, 0, dtInt64,  dtInt64);

  AddFetchConverter(liteNumber, -1, -1,  1, -1, dtFloat);
  AddFetchConverter(liteNumber, -1, -1,  1, -1, dtCurrency);
  AddFetchConverter(liteNumber, -1, -1,  1, -1, dtBCD);
{$IFNDEF FPC}
  AddFetchConverter(liteNumber, -1, -1,  1, -1, dtFmtBCD);
{$ENDIF}

  AddFetchConverter(liteBinary, dtString);
  AddFetchConverter(liteBinary, dtWideString);

  AddFetchConverter(liteVarBinary, dtString);
  AddFetchConverter(liteVarBinary, dtWideString);

  AddFetchConverter(liteDate, dtDateTime);

  AddFetchConverter(liteTime, dtDateTime);

  AddFetchConverter(liteDateTime, dtTime);
  AddFetchConverter(liteDateTime, dtDate);

  AddFetchConverter(liteTimeStamp, dtTime);
  AddFetchConverter(liteTimeStamp, dtDate);
  AddFetchConverter(liteTimeStamp, dtDateTime);

  // liteNull can be mapped to any of the data type
  // because SQLite can return the NULL field type for any field of a non-standard type
  // for example, for calulated fields (like "select FIELD1 + FIELD2 from ...")
  // so user must have the ability to map such fields to anything he wants

  AddFetchConverter(liteNull, dtUnknown);
  AddFetchConverter(liteNull, dtBoolean);
  AddFetchConverter(liteNull, dtMemo);
  AddFetchConverter(liteNull, dtWideMemo);
  AddFetchConverter(liteNull, dtString,     dtMemo);
  AddFetchConverter(liteNull, dtWideString, dtWideMemo);
  AddFetchConverter(liteNull, dtInt8);
  AddFetchConverter(liteNull, dtInt16);
  AddFetchConverter(liteNull, dtUInt16);
  AddFetchConverter(liteNull, dtInt32);
  AddFetchConverter(liteNull, dtUInt32);
  AddFetchConverter(liteNull, dtInt64);
  AddFetchConverter(liteNull, dtBCD);
{$IFNDEF FPC}
  AddFetchConverter(liteNull, dtFMTBCD);
{$ENDIF}
  AddFetchConverter(liteNull, dtFloat);
  AddFetchConverter(liteNull, dtCurrency);
  AddFetchConverter(liteNull, dtDate);
  AddFetchConverter(liteNull, dtTime);
  AddFetchConverter(liteNull, dtDateTime);
  AddFetchConverter(liteNull, dtBytes);
  AddFetchConverter(liteNull, dtVarBytes);

  AddOnDemandConverter(dtFloat, dtDateTime, TLiteDataConverters.RealToDateTime, TLiteDataConverters.DateTimeToReal);
  AddOnDemandConverter(dtInteger, dtDateTime, TLiteDataConverters.IntToDateTime, TLiteDataConverters.DateTimeToInt);
end;

class function TLiteConverterManager.GetDBProvider: Word;
begin
  Result := liteBase;
end;

class function TLiteConverterManager.GetDBType(var SQLTypeName: string): Word;
begin
  //
  if (SQLTypeName = 'NULL')
  then
    Result := liteNull
  else
  if (SQLTypeName = 'INT2') or
     AnsiStartsStr('SMALLINT', SQLTypeName) or
     AnsiStartsStr('SMALL INT', SQLTypeName)
  then
    Result := liteSmallint // Int16
  else
  if AnsiStartsStr('TINYINT', SQLTypeName) or
     AnsiStartsStr('TINY INT', SQLTypeName)
  then
    Result := liteTinyInt // Int8
  else
  if AnsiStartsStr('BIGINT', SQLTypeName) or
     AnsiStartsStr('BIG INT', SQLTypeName)
  then
    Result := liteBigInt // Int64
  else
  if AnsiStartsStr('UNSIGNED BIGINT', SQLTypeName) or
     AnsiStartsStr('UNSIGNED BIG INT', SQLTypeName) or
     (SQLTypeName = 'INT8') or
     (SQLTypeName = 'INT64')
  then
    Result := liteUBigInt // Int64
  else
  if (SQLTypeName = 'INTEGER')
  then
    Result := liteInteger // native INTEGER
  else
  if (SQLTypeName = 'INT')
  then
    Result := liteInt   // Int32
  else
  if AnsiStartsStr('MEDIUMINT', SQLTypeName) or
     AnsiStartsStr('MEDIUM INT', SQLTypeName)
  then
    Result := liteMediumInt // Int32
  else
  // other integers
  if Pos('INT', SQLTypeName) > 0
  then
    Result := liteInt       // Int32
  else
  if (Pos('VARCHAR', SQLTypeName) > 0) then
    Result := liteVarChar
  else
  if (Pos('CHAR', SQLTypeName) > 0) then
    Result := liteChar
  else
  if SQLTypeName = 'TEXT'
  then
    Result := liteText
  else
  if AnsiStartsStr('CLOB', SQLTypeName)
  then
    Result := liteClob
  else
  if SQLTypeName = 'BLOB'
  then
    Result := liteBlob
  else
  if AnsiStartsStr('FLOAT', SQLTypeName)
  then
    Result := liteFloat
  else
  if SQLTypeName = 'REAL'
  then
    Result := liteReal
  else
  if AnsiStartsStr('DOUBLE', SQLTypeName)
  then
    Result := liteDouble
  else
  if SQLTypeName = 'NUMERIC' then
    Result := liteNumeric
  else
  if SQLTypeName = 'DECIMAL' then
    Result := liteDecimal
  else
  if SQLTypeName = 'NUMBER' then
    Result := liteNumber
  else
  if SQLTypeName = 'MONEY'
  then
    Result := liteMoney
  else
  if AnsiStartsStr('BOOL', SQLTypeName)
  then
    Result := liteBool
  else
  if SQLTypeName = 'BINARY'
  then
    Result := liteBinary
  else
  if SQLTypeName = 'VARBINARY'
  then
    Result := liteVarBinary
  else
  if SQLTypeName = 'DATE'
  then
    Result := liteDate
  else
  if SQLTypeName = 'TIME'
  then
    Result := liteTime
  else
  if (SQLTypeName = 'DATETIME')
  then
    Result := liteDateTime
  else
  if (SQLTypeName = 'TIMESTAMP')
  then
    Result := liteTimestamp
  else
    Result := liteNull;
end;

class function TLiteConverterManager.GetDBType(SQLType: integer): Word;
begin
  Result := liteNull;
  case SQLType of
    SQLITE_INTEGER:
      Result := liteInteger;
    SQLITE_FLOAT:
      Result := liteFloat;
    SQLITE_TEXT:
      Result := liteText;
    SQLITE_BLOB:
      Result := liteBlob;
    SQLITE_NULL:
      Result := liteNull;
  else
    Assert(False);
  end;
end;

{ TLiteDataConverters }

class function TLiteDataConverters.DateTimeToReal(
  StringHeap: TStringHeap; Source: IntPtr; SourceLen, SourceScale: Integer;
  Dest: IntPtr; DestLen, DestScale: Integer; IgnoreConvertErrors: Boolean): TConvertStatus;
var
  dt: TDateTime;
{$IFDEF CLR}
  d: Int64;
{$ELSE}{$IFDEF FPC}
  d: Int64;
{$ELSE}
  d: Double;
{$ENDIF}{$ENDIF}
begin
{$IFDEF CLR}
  d := Marshal.ReadInt64(Source);
{$ELSE}{$IFDEF FPC}
  d := Marshal.ReadInt64(Source);
{$ELSE}
  d := BitConverter.Int64BitsToDouble(Marshal.ReadInt64(Source));
{$ENDIF}{$ENDIF}
  dt := TimeStampToDateTime(MSecsToTimeStamp(d));
  Marshal.WriteInt64(Dest, BitConverter.DoubleToInt64Bits(DateTimeToJulianDate(dt)));
  Result := csSuccess;
end;

class function TLiteDataConverters.RealToDateTime(
  StringHeap: TStringHeap; Source: IntPtr; SourceLen, SourceScale: Integer;
  Dest: IntPtr; DestLen, DestScale: Integer; IgnoreConvertErrors: Boolean): TConvertStatus;
var
  dt: TDateTime;
begin
  dt := JulianDateToDateTime(BitConverter.Int64BitsToDouble(Marshal.ReadInt64(Source)));
  Marshal.WriteInt64(Dest, BitConverter.DoubleToInt64Bits(TimeStampToMSecs(DateTimeToTimeStamp(dt))));
  Result := csSuccess;
end;

class function TLiteDataConverters.DateTimeToInt(
  StringHeap: TStringHeap; Source: IntPtr; SourceLen, SourceScale: Integer;
  Dest: IntPtr; DestLen, DestScale: Integer; IgnoreConvertErrors: Boolean): TConvertStatus;
var
  dt: TDateTime;
{$IFDEF CLR}
  d: Int64;
{$ELSE}{$IFDEF FPC}
 d: Int64;
{$ELSE}
  d: Double;
{$ENDIF}{$ENDIF}
begin
{$IFDEF CLR}
  d := Marshal.ReadInt64(Source);
{$ELSE}{$IFDEF FPC}
  d := Marshal.ReadInt64(Source);
{$ELSE}
  d := BitConverter.Int64BitsToDouble(Marshal.ReadInt64(Source));
{$ENDIF}{$ENDIF}
  dt := TimeStampToDateTime(MSecsToTimeStamp(d));
  Marshal.WriteInt64(Dest, DateTimeToUnix(dt));
  Result := csSuccess;
end;

class function TLiteDataConverters.IntToDateTime(
  StringHeap: TStringHeap; Source: IntPtr; SourceLen, SourceScale: Integer;
  Dest: IntPtr; DestLen, DestScale: Integer; IgnoreConvertErrors: Boolean): TConvertStatus;
var
  dt: TDateTime;
begin
  dt := UnixToDateTime(Integer(Marshal.ReadInt64(Source)));
  Marshal.WriteInt64(Dest, BitConverter.DoubleToInt64Bits(TimeStampToMSecs(DateTimeToTimeStamp(dt))));
  Result := csSuccess;
end;

initialization
  InitLiteTypes;
  LiteConverterManager := TLiteConverterManager.Create;

finalization
  LiteConverterManager.Free;

end.
