{-------------------------------------------------------------------------------
 
 Copyright (c) 1999-2009 Ralf Junker, The Delphi Inspiration
 Internet: http://www.yunqa.de/delphi/
 E-Mail:   delphi@yunqa.de

-------------------------------------------------------------------------------}

unit DISQLite3Functions;

{$I DI.inc}
{$I DISQLite3.inc}

{$IFDEF DISQLite3_Personal}
!!! This unit requires the sqlite3_create_function API which is unavailable in       !!!
!!! DISQLite3 Personal. To compile, download DISQLite3 Pro from www.yunqa.de/delphi/ !!!
{$ENDIF DISQLite3_Personal}

interface

uses
  DISystemCompat, SysUtils, DISQLite3Api;

procedure sqlite3_create_math_functions(const ADBHandle: TDISQLite3DatabaseHandle);

procedure sqlite3_function_acos(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);

procedure sqlite3_function_asin(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);

procedure sqlite3_function_atan(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);

procedure sqlite3_function_atan2(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);

procedure sqlite3_function_ceiling(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);

procedure sqlite3_function_cos(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);

procedure sqlite3_function_cot(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);

procedure sqlite3_function_degrees(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);

procedure sqlite3_function_exp(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);

procedure sqlite3_function_floor(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);

procedure sqlite3_function_ln(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);

procedure sqlite3_function_logN(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);

procedure sqlite3_function_log2(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);

procedure sqlite3_function_log10(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);

procedure sqlite3_function_mod(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);

procedure sqlite3_function_pi(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);

procedure sqlite3_function_pow(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);

procedure sqlite3_function_radians(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);

procedure sqlite3_function_sign(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);

procedure sqlite3_function_sin(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);

procedure sqlite3_function_sqrt(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);

procedure sqlite3_function_tan(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);

procedure sqlite3_function_truncate(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);

implementation

uses
  SysConst;

const
  Pi = 3.1415926535897932384626433832795;

function ACos(x: Double): Double; assembler;
asm
  FLD     X
  FLD     ST(0)
  FMUL    ST(0), ST
  FLD1
  FSUBRP  ST(1), ST
  FSQRT
  FXCH
  FPATAN
  FWAIT
end;

function ASin(x: Double): Double; assembler;
asm
  FLD     X
  FLD     ST(0)
  FMUL    ST(0), ST
  FLD1
  FSUBRP  ST(1), ST
  FSQRT
  FPATAN
  FWAIT
end;

function ATan(x: Double): Double; assembler;
asm
  FLD     X
  FLD1
  FPATAN
  FWAIT
end;

function ATan2(y, x: Double): Double; assembler;
asm
  FLD     Y
  FLD     X
  FPATAN
  FWAIT
end;

function Ceil(const x: Double): Int64;
begin
  Result := Int64(Trunc(x));
  if Frac(x) > 0 then
    Inc(Result);
end;

function Cos(x: Double): Double; assembler;
asm
  FLD     X
  FCOS
  FWAIT
end;

function Cot(x: Double): Double; assembler;
asm
  FLD     X
  FPTAN
  FDIVRP
  FWAIT
end;

function Floor(const x: Double): Int64;
begin
  Result := Trunc(x);
  if Frac(x) < 0 then
    Dec(Result);
end;

function log10(x: Double): Double; assembler;
asm
  FLDLG2
  FLD     X
  FYL2X
  FWAIT
end;

function Log2(x: Double): Double; assembler;
asm
  FLD1
  FLD     X
  FYL2X
  FWAIT
end;

function LogN(Base, x: Double): Double; assembler;
asm
  FLD1
  FLD     X
  FYL2X
  FLD1
  FLD     Base
  FYL2X
  FDIV
  FWAIT
end;

function ModDouble(const x, y: Double): Double;
var
  z: Double;
begin
  Result := x / y;
  z := Trunc(Result);
  if Frac(Result) < 0.0 then
    z := z - 1;
  Result := x - y * z;
end;

function Power(const Base, Exponent: Double): Double;
begin
  if (Exponent = 0.0) or (Base = 1.0) then
    Result := 1
  else
    if Base = 0.0 then
      begin
        if Exponent > 0.0 then
          Result := 0.0
        else
          raise EOverflow.Create(SOverflow);
      end
    else
      if Base > 0.0 then
        Result := Exp(Exponent * Ln(Base))
      else
        if Frac(Exponent) = 0.0 then
          begin
            Result := Exp(Exponent * Ln(Abs(Base)));
            if Abs(Round(ModDouble(Exponent, 2))) = 1 then
              Result := -Result;
          end
        else
          raise EInvalidOp.Create(SInvalidOp);
end;

function Sin(x: Double): Double; assembler;
asm
  FLD     X
  FSIN
  FWAIT
end;

function Tan(x: Double): Double; assembler;
asm
  FLD     X
  FPTAN
  FSTP    ST(0)
  FWAIT
end;

const
  WRONG_ARGUMENT_TYPE = 'Wrong argument type';

procedure sqlite3_result_argument_error(const pCtx: sqlite3_context);
begin
  sqlite3_result_error(pCtx, WRONG_ARGUMENT_TYPE, Length(WRONG_ARGUMENT_TYPE));
end;

procedure sqlite3_function_acos(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);
var
  p: Pointer;
  v: Double;
begin
  p := Args[0];
  case sqlite3_value_type(p) of
    SQLITE_INTEGER, SQLITE_FLOAT:
      begin
        v := sqlite3_value_double(p);
        if (v < -1.0) or (v > 1.0) then
          sqlite3_result_null(pCtx)
        else
          sqlite3_result_double(pCtx, ACos(v));
      end;
  else
    sqlite3_result_argument_error(pCtx);
  end;
end;

procedure sqlite3_function_asin(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);
var
  p: Pointer;
  v: Double;
begin
  p := Args[0];
  case sqlite3_value_type(p) of
    SQLITE_INTEGER, SQLITE_FLOAT:
      begin
        v := sqlite3_value_double(p);
        if (v < -1.0) or (v > 1.0) then
          sqlite3_result_null(pCtx)
        else
          sqlite3_result_double(pCtx, ASin(v));
      end;
  else
    sqlite3_result_argument_error(pCtx);
  end;
end;

procedure sqlite3_function_atan(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);
var
  p: Pointer;
begin
  p := Args[0];
  case sqlite3_value_type(p) of
    SQLITE_INTEGER, SQLITE_FLOAT:
      begin
        sqlite3_result_double(pCtx, ATan(sqlite3_value_double(p)));
      end;
  else
    sqlite3_result_argument_error(pCtx);
  end;
end;

procedure sqlite3_function_atan2(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);
var
  p1, p2: Pointer;
begin
  p1 := Args[0];
  case sqlite3_value_type(p1) of
    SQLITE_INTEGER, SQLITE_FLOAT:
      begin
        p2 := Args[1];
        case sqlite3_value_type(p2) of
          SQLITE_INTEGER, SQLITE_FLOAT:
            begin
              sqlite3_result_double(pCtx, ATan2(sqlite3_value_double(p1), sqlite3_value_double(p2)));
              Exit;
            end;
        end;
      end;
  end;
  sqlite3_result_argument_error(pCtx);
end;

procedure sqlite3_function_ceiling(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);
var
  p: Pointer;
begin
  p := Args[0];
  case sqlite3_value_type(p) of
    SQLITE_INTEGER, SQLITE_FLOAT:
      sqlite3_result_int64(pCtx, Ceil(sqlite3_value_double(p)));
  else
    sqlite3_result_argument_error(pCtx);
  end;
end;

procedure sqlite3_function_cos(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);
var
  p: Pointer;
begin
  p := Args[0];
  case sqlite3_value_type(p) of
    SQLITE_INTEGER, SQLITE_FLOAT:
      sqlite3_result_double(pCtx, Cos(sqlite3_value_double(p)));
  else
    sqlite3_result_argument_error(pCtx);
  end;
end;

procedure sqlite3_function_cot(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);
var
  p: Pointer;
begin
  p := Args[0];
  case sqlite3_value_type(p) of
    SQLITE_INTEGER, SQLITE_FLOAT:
      try
        sqlite3_result_double(pCtx, Cot(sqlite3_value_double(p)));
      except
        on e: EMathError do
          sqlite3_result_null(pCtx);
      end;
  else
    sqlite3_result_argument_error(pCtx);
  end;
end;

procedure sqlite3_function_degrees(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);
var
  p: Pointer;
begin
  p := Args[0];
  case sqlite3_value_type(p) of
    SQLITE_INTEGER, SQLITE_FLOAT:
      sqlite3_result_double(pCtx, sqlite3_value_double(p) * 180.0 / Pi);
  else
    sqlite3_result_argument_error(pCtx);
  end;
end;

procedure sqlite3_function_exp(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);
var
  p: Pointer;
begin
  p := Args[0];
  case sqlite3_value_type(p) of
    SQLITE_INTEGER, SQLITE_FLOAT:
      sqlite3_result_double(pCtx, Exp(sqlite3_value_double(p)))
  else
    sqlite3_result_argument_error(pCtx);
  end;
end;

procedure sqlite3_function_floor(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);
var
  p: Pointer;
begin
  p := Args[0];
  case sqlite3_value_type(p) of
    SQLITE_INTEGER, SQLITE_FLOAT:
      sqlite3_result_int64(pCtx, Floor(sqlite3_value_double(p)));
  else
    sqlite3_result_argument_error(pCtx);
  end;
end;

procedure sqlite3_function_ln(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);
var
  p: Pointer;
  v: Double;
begin
  p := Args[0];
  case sqlite3_value_type(p) of
    SQLITE_INTEGER, SQLITE_FLOAT:
      begin
        v := sqlite3_value_double(p);
        if v > 0.0 then
          sqlite3_result_double(pCtx, Ln(v))
        else
          sqlite3_result_null(pCtx);
      end;
  else
    sqlite3_result_argument_error(pCtx);
  end;
end;

procedure sqlite3_function_log10(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);
var
  p: Pointer;
  v: Double;
begin
  p := Args[0];
  case sqlite3_value_type(p) of
    SQLITE_INTEGER, SQLITE_FLOAT:
      begin
        v := sqlite3_value_double(p);
        if v > 0.0 then
          sqlite3_result_double(pCtx, log10(v))
        else
          sqlite3_result_null(pCtx);
      end;
  else
    sqlite3_result_argument_error(pCtx);
  end;
end;

procedure sqlite3_function_log2(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);
var
  p: Pointer;
  v: Double;
begin
  p := Args[0];
  case sqlite3_value_type(p) of
    SQLITE_INTEGER, SQLITE_FLOAT:
      begin
        v := sqlite3_value_double(p);
        if v > 0.0 then
          sqlite3_result_double(pCtx, Log2(v))
        else
          sqlite3_result_null(pCtx);
      end;
  else
    sqlite3_result_argument_error(pCtx);
  end;
end;

procedure sqlite3_function_logN(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);
label
  ResultNull;
var
  p1, p2: Pointer;
  v1, v2: Double;
begin
  p1 := Args[0];
  if sqlite3_value_type(p1) in [SQLITE_INTEGER, SQLITE_FLOAT] then
    begin
      v1 := sqlite3_value_double(p1);
      if (v1 > 0.0) and (v1 <> 1.0) then
        begin
          p2 := Args[1];
          if sqlite3_value_type(p2) in [SQLITE_INTEGER, SQLITE_FLOAT] then
            begin
              v2 := sqlite3_value_double(p2);
              if v2 > 0.0 then
                sqlite3_result_double(pCtx, LogN(v1, v2))
              else
                ResultNull:
                sqlite3_result_null(pCtx);
              Exit;
            end;
        end
      else
        goto ResultNull;
    end;
  sqlite3_result_argument_error(pCtx);
end;

procedure sqlite3_function_mod(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);
label
  1;
var
  p1, p2: Pointer;
begin
  p1 := Args[0];
  case sqlite3_value_type(p1) of

    SQLITE_INTEGER:
      begin
        p2 := Args[1];
        case sqlite3_value_type(p2) of
          SQLITE_INTEGER:
            begin
              sqlite3_result_int64(pCtx, sqlite3_value_int64(p1) mod sqlite3_value_int64(p2));
              Exit;
            end;
          SQLITE_FLOAT:
            goto 1;
        end;
      end;

    SQLITE_FLOAT:
      begin
        p2 := Args[1];
        case sqlite3_value_type(p2) of
          SQLITE_INTEGER, SQLITE_FLOAT:
            begin
              1:
              sqlite3_result_double(pCtx, ModDouble(sqlite3_value_double(p1), sqlite3_value_double(p2)));
              Exit;
            end;
        end;
      end;
  end;
  sqlite3_result_argument_error(pCtx);
end;

procedure sqlite3_function_pi(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);
begin
  sqlite3_result_double(pCtx, Pi);
end;

procedure sqlite3_function_pow(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);
label
  ResultNull;
var
  p1, p2: Pointer;
begin
  p1 := Args[0];
  if sqlite3_value_type(p1) in [SQLITE_INTEGER, SQLITE_FLOAT] then
    begin
      p2 := Args[1];
      if sqlite3_value_type(p2) in [SQLITE_INTEGER, SQLITE_FLOAT] then
        begin
          try
            sqlite3_result_double(pCtx, Power(sqlite3_value_double(p1), sqlite3_value_double(p2)));
          except
            on e: EMathError do
              sqlite3_result_null(pCtx);
          end;
          Exit;
        end;
    end;
  sqlite3_result_argument_error(pCtx);
end;

procedure sqlite3_function_radians(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);
var
  p: Pointer;
begin
  p := Args[0];
  case sqlite3_value_type(p) of
    SQLITE_INTEGER, SQLITE_FLOAT:
      sqlite3_result_double(pCtx, sqlite3_value_double(p) * Pi / 180.0);
  else
    sqlite3_result_argument_error(pCtx);
  end;
end;

procedure sqlite3_function_sign(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);
var
  p: Pointer;
  d: Double;
  i: Int64;
  r: Integer;
begin
  p := Args[0];
  case sqlite3_value_type(p) of

    SQLITE_INTEGER:
      begin
        i := sqlite3_value_int64(p);
        if i < 0 then
          r := -1
        else
          if i > 0 then
            r := 1
          else
            r := 0;
        sqlite3_result_int(pCtx, r);
      end;

    SQLITE_FLOAT:
      begin
        d := sqlite3_value_double(p);
        if d < 0 then
          r := -1
        else
          if d > 0 then
            r := 1
          else
            r := 0;
        sqlite3_result_int(pCtx, r);
      end;

  else
    sqlite3_result_argument_error(pCtx);
  end;
end;

procedure sqlite3_function_sin(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);
var
  p: Pointer;
begin
  p := Args[0];
  case sqlite3_value_type(p) of
    SQLITE_INTEGER, SQLITE_FLOAT:
      sqlite3_result_double(pCtx, Sin(sqlite3_value_double(p)));
  else
    sqlite3_result_argument_error(pCtx);
  end;
end;

procedure sqlite3_function_sqrt(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);
var
  p: Pointer;
  v: Double;
begin
  p := Args[0];
  case sqlite3_value_type(p) of
    SQLITE_INTEGER, SQLITE_FLOAT:
      begin
        v := sqlite3_value_double(p);
        if v >= 0.0 then
          sqlite3_result_double(pCtx, Sqrt(v))
        else
          sqlite3_result_null(pCtx);
      end;
  else
    sqlite3_result_argument_error(pCtx);
  end;
end;

procedure sqlite3_function_tan(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);
var
  p: Pointer;
begin
  p := Args[0];
  case sqlite3_value_type(p) of
    SQLITE_INTEGER, SQLITE_FLOAT:
      sqlite3_result_double(pCtx, Tan(sqlite3_value_double(p)));
  else
    sqlite3_result_argument_error(pCtx);
  end;
end;

procedure sqlite3_function_truncate(pCtx: sqlite3_context; nArgs: Integer; Args: PPointerArray);
const
  PowerInt10: array[1..18] of Int64 = (
    10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000,
    10000000000, 100000000000, 1000000000000, 10000000000000, 100000000000000,
    1000000000000000, 10000000000000000, 100000000000000000, 1000000000000000000);
var
  p: Pointer;
  e, e10: Extended;
  i, i10: Int64;
  d: Integer;
begin
  p := Args[0];
  case sqlite3_value_type(p) of
    SQLITE_NULL:
      begin
        sqlite3_result_null(pCtx);
      end;

    SQLITE_INTEGER:
      begin
        i := sqlite3_value_int(p);
        if nArgs = 2 then
          begin
            d := -sqlite3_value_int(Args[1]);
            if d > 0 then
              begin
                if d > High(PowerInt10) then
                  d := High(PowerInt10);
                i10 := PowerInt10[d];
                i := i div i10 * i10;
              end;
          end;
        sqlite3_result_int64(pCtx, i);
      end;

  else
    e := sqlite3_value_double(p);
    if nArgs = 2 then
      begin
        d := sqlite3_value_int(Args[1]);
        if d > 20 then
          d := 20
        else
          if d < -20 then
            d := -20;
      end
    else
      begin
        d := 0;
      end;

    if d = 0 then
      e := Trunc(e)
    else
      begin
        e10 := Power10(d);
        e := Trunc(e * e10) / e10
      end;
    sqlite3_result_double(pCtx, e);
  end;
end;

procedure sqlite3_create_math_functions(const ADBHandle: TDISQLite3DatabaseHandle);
begin
  if Assigned(ADBHandle) then
    begin
      sqlite3_check(sqlite3_create_function(ADBHandle, 'acos', 1, 0, nil, sqlite3_function_acos, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'asin', 1, 0, nil, sqlite3_function_asin, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'atan', 1, 0, nil, sqlite3_function_atan, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'atan', 2, 0, nil, sqlite3_function_atan2, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'atan2', 2, 0, nil, sqlite3_function_atan2, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'ceil', 1, 0, nil, sqlite3_function_ceiling, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'ceiling', 1, 0, nil, sqlite3_function_ceiling, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'cos', 1, 0, nil, sqlite3_function_cos, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'cot', 1, 0, nil, sqlite3_function_cot, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'degrees', 1, 0, nil, sqlite3_function_degrees, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'exp', 1, 0, nil, sqlite3_function_exp, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'floor', 1, 0, nil, sqlite3_function_floor, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'ln', 1, 0, nil, sqlite3_function_ln, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'log', 1, 0, nil, sqlite3_function_ln, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'log', 2, 0, nil, sqlite3_function_logN, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'log2', 1, 0, nil, sqlite3_function_log2, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'log10', 1, 0, nil, sqlite3_function_log10, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'mod', 2, 0, nil, sqlite3_function_mod, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'pi', 0, 0, nil, sqlite3_function_pi, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'pow', 2, 0, nil, sqlite3_function_pow, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'radians', 1, 0, nil, sqlite3_function_radians, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'sign', 1, 0, nil, sqlite3_function_sign, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'sin', 1, 0, nil, sqlite3_function_sin, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'sqrt', 1, 0, nil, sqlite3_function_sqrt, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'tan', 1, 0, nil, sqlite3_function_tan, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'truncate', 1, 0, nil, sqlite3_function_truncate, nil, nil), ADBHandle);
      sqlite3_check(sqlite3_create_function(ADBHandle, 'truncate', 2, 0, nil, sqlite3_function_truncate, nil, nil), ADBHandle);
    end;
end;

end.

