(*
/*

CLASS {NATIVE_DB|_Delphi_VCL}, NATIVE, UNTESTED,
ABSTRACT:

IMPORT: {System_functions} .

NATIVE: "///COPY AL4_options.inc" .

FUN Check_blobs_are_supported ==> BOOL :  RESULT = TRUE .

TEST of_supported:
     ASSERT Check_blobs_are_supported .

*/
*)
unit NATIVE_DB;

{$IFDEF FPC}
	{$DEFINE ODBC}
	{$DEFINE NO_ADO}
{$ELSE}
	{$IFnDEF ODBC}
		{$DEFINE ADO}
	{$ENDIF}
{$ENDIF}

interface uses
	{$IFDEF LINUX}
	{$ELSE} Windows, 
	{$ENDIF} Classes, SysUtils, 
			   AL4, 
			   DB,
	{$IFDEF ODBC}
		{$IFDEF FPC}
		odbcconn, 
		sqldb, 
		strutils,
		{$ENDIF}
	{$ELSE}
		AdoDB, ActiveX,
	{$ENDIF}
	{$IFDEF FPC}
	{$ELSE} FMTBcd,
	{$ENDIF}
	All_classes, Variants;
	
{$I AL4_options.inc}

type
    TNATIVE_DB = class
    public 
        use_OleDb: Boolean;
        Connection_string: String;
        {$IFDEF ODBC}
	        S_c: TODBCConnection;
	        S_t: TSQLTransaction;
	        T_level: Integer;
	        auto_tran: Boolean;
	        Sql: TSQLQuery;
        {$ELSE}
	        S_c: TAdoConnection;
	        Sql: TAdoQuery;
        {$ENDIF}
    end;

function DB_Create_connection(const Connection, User: String;
         Provider_1_OLE: Integer): Integer;
procedure DB_Destroy_connection(Handle: Integer);
function DB_Connect(Handle: Integer; const Password: String): Boolean;
procedure DB_Disconnect(Handle: Integer);
function DB_Is_connected(Handle: Integer): Boolean;
procedure DB_Begin_transaction(Handle: Integer);
procedure DB_End_transaction(Handle: Integer; Commited: Boolean);

function DB_Execute(Handle: Integer; const Sql_text: String;
         Blobs: DynAObj): Integer;
procedure DB_Close(Handle: Integer);
function DB_Open(Handle: Integer; const Sql_text: String): Boolean;
function DB_Next(Handle: Integer): Boolean;

function DB_Count_fields(Handle: Integer): Integer;
function DB_Field_name_by_index(Handle, Indx: Integer): String;
function DB_Integer(Handle, Indx: Integer): Integer;
function DB_Real(Handle, Indx: Integer): Double;
procedure DB_Id(Handle, Indx: Integer; Value: DynAInt);
function DB_Date_time(Handle, Indx: Integer): TDateTime;
function DB_Boolean(Handle, Indx: Integer): Boolean;
function DB_Is_null(Handle, Indx: Integer): Boolean;
function DB_String(Handle, Indx: Integer): String;

procedure DB_Setup_blob_param(Handle: Integer; X_Blob: Ref_obj;
          Index_blob: Integer );
          
type
    TBlobReader = class(TStream)
    public
        CBlob: C_Blob;
        constructor Create(B: C_Blob);
        function Seek(
        	{$IFDEF _D6orHigher} const Offset: Int64 
        	{$ELSE} Offset: Longint {$ENDIF} ;
        	Origin: {$IFDEF _D6orHigher} TSeekOrigin {$ELSE} Word {$ENDIF} )
        	: {$IFDEF _D6orHigher} Int64 {$ELSE} Longint {$ENDIF} ; 
            override;
        function Read(var Buffer; Count: Longint): Longint; override;
        function Write(const Buffer; Count: Longint): Longint; override;
    end;

implementation

{$IFDEF USE_LISTS_OF_DESCRIPTORS}
var All_db: TList;

function alloc_db(F: TNATIVE_DB): Integer;
begin
	if All_db = nil then All_db := TList.Create;
	Result := All_db.IndexOf(nil);
	if Result < 0 then begin
		Result := All_db.Count;
		All_db.Add(F);
	end
		else
	All_db[Result] := F;
end;
{$ENDIF}

constructor TBlobReader.Create(
	B: C_Blob);
begin
    inherited Create;
    CBlob := B;
end;

function TBlobReader.Seek(
        	{$IFDEF _D6orHigher} const Offset: Int64 
        	{$ELSE} Offset: Longint {$ENDIF} ;
        	Origin: {$IFDEF _D6orHigher} TSeekOrigin {$ELSE} Word {$ENDIF} )
        	: {$IFDEF _D6orHigher} Int64 {$ELSE} Longint {$ENDIF} ;
var off_to: st_long__C_Long_int;
	new_pos: st_long__C_Long_int;
begin
	off_to.F_Lo := Offset;
	off_to.F_Hi := {$IFDEF _D6orHigher} Offset shr 32
				   {$ELSE} 0
				   {$ENDIF} ;
    CBlob.M_Set_pos(off_to, Integer(Origin));
    new_pos := CBlob.M_Position;
    RESULT := new_pos.F_Lo
    		{$IFDEF _D6orHigher}
    			or (Int64(new_pos.F_Hi) shl 32)
    		{$ENDIF} ;
end;

function TBlobReader.Read(
	var Buffer; Count: Longint): Longint;
var buf: DynAByte;
    bytes: PByte;
begin
    bytes := Pointer(@Buffer);
    buf := New_FixAByte_Array(nil, bytes, Count, 0, Count-1);
    try
        Result := CBlob.M_Read_bytes(buf);
    finally
        buf.Free;
    end;
end;

function TBlobReader.Write(
	const Buffer; Count: Longint): Longint;
begin Result := 0; end;

function DB_Create_connection(const Connection, User: String;
         Provider_1_OLE: Integer): Integer;
var db: TNATIVE_DB;
begin
	{$IFDEF ADO}
    CoInitialize(nil);
    {$ENDIF}
    db := TNATIVE_DB.Create;
    db.Connection_string := Connection;
    if User <> '' then
        db.Connection_string := Connection + ';User=' + User;
    db.use_OleDb := Provider_1_OLE = 1;
    {$IFDEF USE_LISTS_OF_DESCRIPTORS}
    	RESULT := alloc_db(db);
    {$ELSE}
    	RESULT := Integer(db);
    {$ENDIF}
end;

procedure DB_Destroy_connection(
	Handle: Integer);
var db: TNATIVE_DB;
begin
	{$IFDEF USE_LISTS_OF_DESCRIPTORS}
		db := TNATIVE_DB(All_db[Handle]);
		All_db[Handle] := nil;
	{$ELSE}
    	db := TNATIVE_DB(Handle);
	{$ENDIF}
    try
        if db.Sql <> nil then
        begin
        	{$IFDEF _D6orHigher}
            FreeAndNil(TObject(db.Sql));
            {$ELSE}
            db.Sql.Free;
            db.Sql := nil;
            {$ENDIF}
        end;
        if db.S_c <> nil then 
    	begin
    		{$IFDEF _D6orHigher}
            FreeAndNil(TObject(db.S_c));
            {$ELSE}
            db.S_c.Free;
            db.S_c := nil;
            {$ENDIF}
    	end;
        db.Free;
    except on E: Exception do
           begin
                Any_Exception(E);
           end;
    end;
    {$IFDEF ADO}
    CoUninitialize;
    {$ENDIF}
end;

function starts{_case_insensitive}(
	const s: String;
	const w{should_be_lowercased}: String): Boolean;
begin
	Result := (Length(s) >= Length(w)) and
		(Copy(Lowercase(s), 1, Length(w)) = w); 
end;

function DB_Connect(
	Handle: Integer; const Password: String): Boolean;
var db: TNATIVE_DB;
    c_s: String;
    {$IFDEF ODBC}
    s: String;
    i: Integer;
    {$ENDIF}
begin
    RESULT := TRUE;
	{$IFDEF USE_LISTS_OF_DESCRIPTORS}
		db := TNATIVE_DB(All_db[Handle]);
	{$ELSE}
    	db := TNATIVE_DB(Handle);
	{$ENDIF}
    try
        c_s := db.Connection_string;
        if Password <> '' then c_s := c_s + ';Password=' + Password ;
        
        if db.S_c = nil then
        begin
            db.S_c :=
            	{$IFDEF ODBC}
            	TOdbcConnection.Create(nil);
            	{$ELSE} 
            	TAdoConnection.Create(nil);
            	{$ENDIF}
        end;
        if db.S_c.Connected then Exit;
        
		{$IFDEF ODBC}
		for i := 1 to 100 do
		begin
			s := ExtractWord(i, c_s, [';']);
			if s = '' then break;
			if starts(s, 'driver=') then
			begin
				//Writeln('DRVVVVVVVVVVVVER: ' + Copy(s, 1 + Length('driver=')));
				db.S_c.Driver := Copy(s, 1 + Length('driver='));
				//db.S_c.Params.Add(s);
			end
			else if starts(s, 'databasename=') then
			begin
				//Writeln('DBNNNNNNNNNNNAME: ' + Copy(s, 1 + 
				//	Length('databasename=')));
				db.S_c.DatabaseName := Copy(s, 1 + Length('databasename='));
			end
			else
			begin
				//Writeln('PARRRRRRRRRRAAAM: ' + s);
				db.S_c.Params.Add(s);
			end;
		end;
		//db.S_c.Connected := TRUE;
		db.S_c.KeepConnection := TRUE;
		db.S_c.Open;
		//Writeln('CONNNNNNNNNNNNNNNNNNNECT: ' + 
		//					IntToStr(Integer(db.S_c.Connected)));
		{$ELSE}
        db.S_c.ConnectionString := c_s;
        db.S_c.Open;
        {$ENDIF}
        RESULT := db.S_c.Connected;
    except on E: Exception do
           begin
           		//Writeln('EXXXXXXXXXXXXXXXXCEPTION:' + E.Message);
                Any_Exception(E);
                RESULT := FALSE;
           end;
    end;
end;

procedure DB_Disconnect(
	Handle: Integer);
var db: TNATIVE_DB;
begin
	{$IFDEF USE_LISTS_OF_DESCRIPTORS}
		db := TNATIVE_DB(All_db[Handle]);
	{$ELSE}
    	db := TNATIVE_DB(Handle);
	{$ENDIF}
    try
        if db.S_c = nil then Exit;
        if not db.S_c.Connected then Exit;
        db.S_c.Close;
    except on E: Exception do
           begin
                Any_Exception(E);
           end;
    end;
end;

function DB_Is_connected(
	Handle: Integer): Boolean;
var db: TNATIVE_DB;
begin
    RESULT := FALSE;
	{$IFDEF USE_LISTS_OF_DESCRIPTORS}
		db := TNATIVE_DB(All_db[Handle]);
	{$ELSE}
    	db := TNATIVE_DB(Handle);
	{$ENDIF}
    try
        if db.S_c <> nil then
           RESULT := db.S_c.Connected;
    except on E: Exception do
           begin
                Any_Exception(E);
                RESULT := FALSE;
           end;
    end;
end;


procedure DB_Begin_transaction(
	Handle: Integer);
var db: TNATIVE_DB;
begin
	{$IFDEF USE_LISTS_OF_DESCRIPTORS}
		db := TNATIVE_DB(All_db[Handle]);
	{$ELSE}
    	db := TNATIVE_DB(Handle);
	{$ENDIF}
    try
        if db.S_c = nil then Exit;
        if not db.S_c.Connected then Exit;
        {$IFDEF ODBC}
        if db.S_t <> nil then
        begin
        	inc(db.T_level);
        	Exit;
        end;
        db.S_t := TSQLTransaction.Create(nil);
        db.S_t.Database := db.S_c;
        db.S_c.Transaction := db.S_t;
        db.S_t.Action := caCommit;
        //db.S_t.Active := TRUE; // either the next line
        db.S_t.StartTransaction;
        {$ELSE}
        db.S_c.BeginTrans;
        {$ENDIF}
    except on E: Exception do
           begin
                Any_Exception(E);
           end;
    end;
end;
    
procedure DB_End_transaction(
	Handle: Integer; Commited: Boolean);
var db: TNATIVE_DB;
begin
	{$IFDEF USE_LISTS_OF_DESCRIPTORS}
		db := TNATIVE_DB(All_db[Handle]);
	{$ELSE}
    	db := TNATIVE_DB(Handle);
	{$ENDIF}
    try
        if db.S_c = nil then Exit;
        if not db.S_c.Connected then Exit;
        {$IFDEF ODBC}
        if db.T_level > 0 then
        begin
        	dec(db.T_level);
        	Exit;
        end;
        if Commited then db.S_t.Commit
        			else db.S_t.Rollback;
        //db.S_t.Active := FALSE;
        db.S_t.Free;
        if db.S_c <> nil then db.S_c.Transaction := nil;
        if db.Sql <> nil then db.Sql.Transaction := nil;
        db.S_t := nil;
        {$ELSE}
        if Commited then db.S_c.CommitTrans
                    else db.S_c.RollbackTrans;
        {$ENDIF}
    except on E: Exception do
           begin
                Any_Exception(E);
           end;
    end;
end;

function DB_Execute(
	Handle: Integer; const Sql_text: String;
         Blobs: DynAObj): Integer;
var db: TNATIVE_DB;
    i: Integer;
begin
    RESULT := 0;
	{$IFDEF USE_LISTS_OF_DESCRIPTORS}
		db := TNATIVE_DB(All_db[Handle]);
	{$ELSE}
    	db := TNATIVE_DB(Handle);
	{$ENDIF}
	{$IFDEF ODBC}
	if db.auto_tran then
	begin
		db.auto_tran := FALSE;
		DB_End_transaction(Handle, TRUE);
	end;
	{$ENDIF}
    try
        if db.S_c = nil then Exit;
        if not db.S_c.Connected then Exit;
        {$IFDEF ODBC}
        if db.S_t = nil then
        begin
        	db.auto_tran := TRUE;
        	DB_Begin_transaction(Handle);
        	//Writeln('LET TRANSACTION BEGIN!!!!!!!!!!!!!!')
        end;
        {$ENDIF}
        if db.Sql = nil then
        begin
        	{$IFDEF ODBC}
        	db.Sql := TSQLQuery.Create(nil);
            db.Sql.Database := db.S_c;
            db.Sql.ParseSql := FALSE;
        	{$ELSE}
            db.Sql := TAdoQuery.Create(nil);
            db.Sql.Connection := db.S_c;
            {$ENDIF}
        end;
        db.Sql.SQL.Clear;
        db.Sql.SQL.Add(Sql_text);
        
        for i := 0 to Blobs.Count()-1 do
            DB_Setup_blob_param(Handle, Ref_obj(Blobs.List[i]), i);
            
		{$IFDEF ODBC}
        if db.S_t <> nil then
        begin
        	db.Sql.Transaction := db.S_t;
        end;
        db.Sql.ExecSQL;
        //Writeln('EXXXXXXXXXXXXXECUTED: ' + db.Sql.SQL.Text);
        if db.auto_tran then
        begin
        	db.auto_tran := FALSE;
        	DB_End_transaction(Handle, TRUE);
        	//Writeln('TRANSACTION ENNNNNNNNNDED ');
        end;
        {$ELSE}
        db.Sql.Prepared := true;
        RESULT := db.Sql.ExecSQL;
        {$ENDIF}
    except on E: Exception do
           begin
           		//Writeln('EXXXXXXXXXXXXCEPTIONNNNN: ' + E.Message);
           		{$IFDEF ODBC}
           		if db.auto_tran then
           		begin
           			db.auto_tran := FALSE;
           			DB_End_transaction(Handle, FALSE);
           		end;
           		{$ENDIF}
                //Any_Exception(E);
                Add_error_descr(E.ClassName + ': ' + E.Message 
            	+ #10#13'--query:'#10#13 + Sql_text);
           end;
    end;
end;
    
function DB_Open(
	Handle: Integer; const Sql_text: String): Boolean;
var db: TNATIVE_DB;
begin
    RESULT := FALSE;
	{$IFDEF USE_LISTS_OF_DESCRIPTORS}
		db := TNATIVE_DB(All_db[Handle]);
	{$ELSE}
    	db := TNATIVE_DB(Handle);
	{$ENDIF}
	{$IFDEF ODBC}
	if db.auto_tran then
	begin
    	db.auto_tran := FALSE;
		DB_End_transaction(Handle, TRUE);
	end;
	{$ENDIF}
    try
        if db.S_c = nil then Exit;
        if not db.S_c.Connected then Exit;
        {$IFDEF ODBC}
        if db.S_t = nil then
        begin
        	db.auto_tran := TRUE;
        	DB_Begin_transaction(Handle);
        	//Writeln('LET TRANSACTION BEGIN!!!!!!!!!!!!!!')
        end;
        {$ENDIF}
        if db.Sql = nil then
        begin
        	{$IFDEF ODBC}
            db.Sql := TSQLQuery.Create(nil);
            db.Sql.Database := db.S_c;
            db.Sql.ParseSql := FALSE;
            if db.S_t <> nil then
            	db.Sql.Transaction := db.S_t;
        	{$ELSE}
            db.Sql := TAdoQuery.Create(nil);
            db.Sql.Connection := db.S_c;
            {$ENDIF}
        end;
        if db.Sql.Active then db.Sql.Close;
        db.Sql.SQL.Clear;
        db.Sql.SQL.Add(Sql_text);
        {$IFDEF ODBC}
        if db.S_t <> nil then
        begin
        	db.Sql.Transaction := db.S_t;
        end;
        {$ELSE}
        db.Sql.Prepared := true;
        {$ENDIF}
        db.Sql.Open;
        if not db.Sql.Eof then begin
	        db.Sql.First;
	        RESULT := TRUE;
	        //Writeln('not EOF!');
	        //////////////////////
        end;
    except on E: Exception do
           begin
           		//Writeln('OPENNNNN EXXXXXXXXXXXXCEPTIONNNNN: ' + E.Message);
           		///////////////////////////////////////////////////////////
           		{$IFDEF ODBC}
           		if db.auto_tran then
           		begin
           			db.auto_tran := FALSE;
           			DB_End_transaction(Handle, FALSE);
           		end;
           		{$ENDIF}
                //Any_Exception(E);
                Add_error_descr(E.ClassName + ': ' + E.Message 
            	+ #10#13'--query:'#10#13 + Sql_text);
           end;
    end;
end;

procedure DB_Close(Handle: Integer);
var db: TNATIVE_DB;
begin
	{$IFDEF USE_LISTS_OF_DESCRIPTORS}
		db := TNATIVE_DB(All_db[Handle]);
	{$ELSE}
    	db := TNATIVE_DB(Handle);
	{$ENDIF}
    try
        {$IFDEF ODBC}
        if db.auto_tran then
        begin
        	db.auto_tran := FALSE;
        	DB_End_transaction(Handle, TRUE);
        	//Writeln('TRANSACTION ENNNNNNNNNDED ');
        end;
        {$ENDIF}
        if db.S_c = nil then Exit;
        if not db.S_c.Connected then Exit;
        if db.Sql = nil then Exit;
        if db.Sql.Active then db.Sql.Close;
    except on E: Exception do
           begin
                Any_Exception(E);
           end;
    end;
end;

function DB_Next(
	Handle: Integer): Boolean;
var db: TNATIVE_DB;
begin
    RESULT := false;
	{$IFDEF USE_LISTS_OF_DESCRIPTORS}
		db := TNATIVE_DB(All_db[Handle]);
	{$ELSE}
    	db := TNATIVE_DB(Handle);
	{$ENDIF}
    try
        if db.S_c = nil then Exit;
        if not db.S_c.Connected then Exit;
        if db.Sql = nil then Exit;
        if db.Sql.Eof then Exit;
        db.Sql.Next;
        RESULT := not db.Sql.Eof;
    except on E: Exception do
           begin
                Any_Exception(E);
           end;
    end;
end;

function DB_Count_fields(
	Handle: Integer): Integer;
var db: TNATIVE_DB;
begin
    RESULT := 0;
	{$IFDEF USE_LISTS_OF_DESCRIPTORS}
		db := TNATIVE_DB(All_db[Handle]);
	{$ELSE}
    	db := TNATIVE_DB(Handle);
	{$ENDIF}
    try
        if db.S_c = nil then Exit;
        if not db.S_c.Connected then Exit;
        if db.Sql = nil then Exit;
        //if db.Sql.Eof then Exit;
        RESULT := db.Sql.Fields.Count;
    except on E: Exception do
           begin
                Any_Exception(E);
           end;
    end;
end;

function DB_Field_name_by_index(
	Handle, Indx: Integer): String;
var db: TNATIVE_DB;
begin
    RESULT := '';
	{$IFDEF USE_LISTS_OF_DESCRIPTORS}
		db := TNATIVE_DB(All_db[Handle]);
	{$ELSE}
    	db := TNATIVE_DB(Handle);
	{$ENDIF}
    try
        if db.S_c = nil then Exit;
        if not db.S_c.Connected then Exit;
        if db.Sql = nil then Exit;
        //if db.Sql.Eof then Exit;
        if (Indx < 0) or (Indx >= db.Sql.Fields.Count) then Exit;
        RESULT := db.Sql.Fields[Indx].FieldName;
    except on E: Exception do
           begin
                //Any_Exception(E);
           end;
    end;
end;

function DB_Integer(
	Handle, Indx: Integer): Integer;
var db: TNATIVE_DB;
begin
    RESULT := 0;
	{$IFDEF USE_LISTS_OF_DESCRIPTORS}
		db := TNATIVE_DB(All_db[Handle]);
	{$ELSE}
    	db := TNATIVE_DB(Handle);
	{$ENDIF}
    try
        if db.S_c = nil then Exit;
        if not db.S_c.Connected then Exit;
        if db.Sql = nil then Exit;
        if db.Sql.Eof then Exit;
        if (Indx < 0) or (Indx >= db.Sql.Fields.Count) then Exit;
        RESULT := db.Sql.Fields[Indx].AsInteger;
    except on E: Exception do
           begin
                //Any_Exception(E);
           end;
    end;
end;

function DB_Real(
	Handle, Indx: Integer): Double;
var db: TNATIVE_DB;
	debugBCD: array[0..7] of Byte;
	debug_i : Integer;
begin
    RESULT := 0;
	{$IFDEF USE_LISTS_OF_DESCRIPTORS}
		db := TNATIVE_DB(All_db[Handle]);
	{$ELSE}
    	db := TNATIVE_DB(Handle);
	{$ENDIF}
    try
        if db.S_c = nil then Exit;
        if not db.S_c.Connected then Exit;
        if db.Sql = nil then Exit;
        if db.Sql.Eof then Exit;
        if (Indx < 0) or (Indx >= db.Sql.Fields.Count) then Exit;
        
        //case db.Sql.FieldDefs[Indx].DataType of
        //ftBCD: RESULT := BcdToDouble(db.Sql.Fields[Indx].AsBCD);
        //ftCurrency: RESULT := db.Sql.Fields[Indx].AsCurrency;
        //else RESULT := db.Sql.Fields[Indx].AsFloat;
        //end;
        
		RESULT := db.Sql.Fields[Indx].AsFloat;
		
    except on E: Exception do
           begin
                Any_Exception(E);
                //if db.Sql.FieldDefs[Indx].DataType = ftBCD then
                //begin
                //    db.Sql.Fields[Indx].GetData(@debugBCD);
                //    writeln('debug BCD:');
                //        FOR debug_i := 0 to 7 do
                //            writeln('    byte' + IntToStr(debug_i) + ' = ' +
                //                IntToHex( debugBCD[debug_i], 2));
                //    //writeln('AsStr=' + BCDToStr(debugBCD) );
                //end;
           end;
    end;
end;

procedure DB_Id(Handle, Indx: Integer; Value: DynAInt);
var db: TNATIVE_DB;
	X: Integer;
begin
	{$IFDEF USE_LISTS_OF_DESCRIPTORS}
		db := TNATIVE_DB(All_db[Handle]);
	{$ELSE}
    	db := TNATIVE_DB(Handle);
	{$ENDIF}
    try
        if db.S_c = nil then Exit;
        if not db.S_c.Connected then Exit;
        if db.Sql = nil then Exit;
        if db.Sql.Eof then Exit;
        if (Indx < 0) or (Indx >= db.Sql.Fields.Count) then Exit;
        X := db.Sql.Fields[Indx].AsInteger;

        Value.SetIntegers(0, x);
        if x < 0 then Value.SetIntegers(1, -1)
        else Value.SetIntegers(1, 0);
    except  on E: Exception do
        //Any_exception(E);
    end;
end;


function DB_Date_time(
	Handle, Indx: Integer): TDateTime;
var db: TNATIVE_DB;
begin
    RESULT := 0;
	{$IFDEF USE_LISTS_OF_DESCRIPTORS}
		db := TNATIVE_DB(All_db[Handle]);
	{$ELSE}
    	db := TNATIVE_DB(Handle);
	{$ENDIF}
    try
        if db.S_c = nil then Exit;
        if not db.S_c.Connected then Exit;
        if db.Sql = nil then Exit;
        if db.Sql.Eof then Exit;
        if (Indx < 0) or (Indx >= db.Sql.Fields.Count) then Exit;
        RESULT := db.Sql.Fields[Indx].AsDateTime * 24.0 * 3600000;
    except on E: Exception do
           begin
                //Any_Exception(E);
           end;
    end;
end;

function DB_Boolean(
	Handle, Indx: Integer): Boolean;
var db: TNATIVE_DB;
begin
    RESULT := FALSE;
	{$IFDEF USE_LISTS_OF_DESCRIPTORS}
		db := TNATIVE_DB(All_db[Handle]);
	{$ELSE}
    	db := TNATIVE_DB(Handle);
	{$ENDIF}
    try
        if db.S_c = nil then Exit;
        if not db.S_c.Connected then Exit;
        if db.Sql = nil then Exit;
        if db.Sql.Eof then Exit;
        if (Indx < 0) or (Indx >= db.Sql.Fields.Count) then Exit;
        if VarIsType(db.Sql.Fields[Indx].Value, varBoolean) then
           RESULT := db.Sql.Fields[Indx].AsBoolean
        else if  db.Sql.Fields[Indx].AsString <> '' then
           RESULT := db.Sql.Fields[Indx].AsInteger <> 0;
    except on E: Exception do
           begin
                //Any_Exception(E);
           end;
    end;
end;

function DB_Is_null(
	Handle, Indx: Integer): Boolean;
var db: TNATIVE_DB;
begin
    RESULT := TRUE;
	{$IFDEF USE_LISTS_OF_DESCRIPTORS}
		db := TNATIVE_DB(All_db[Handle]);
	{$ELSE}
    	db := TNATIVE_DB(Handle);
	{$ENDIF}
    try
        if db.S_c = nil then Exit;
        if not db.S_c.Connected then Exit;
        if db.Sql = nil then Exit;
        if db.Sql.Eof then Exit;
        if (Indx < 0) or (Indx >= db.Sql.Fields.Count) then Exit;
        RESULT := db.Sql.Fields[Indx].IsNull;
    except on E: Exception do
           begin
                Any_Exception(E);
           end;
    end;
end;

function DB_String(
	Handle, Indx: Integer): String;
var db: TNATIVE_DB;
begin
    RESULT := '';
	{$IFDEF USE_LISTS_OF_DESCRIPTORS}
		db := TNATIVE_DB(All_db[Handle]);
	{$ELSE}
    	db := TNATIVE_DB(Handle);
	{$ENDIF}
    try
        if db.S_c = nil then Exit;
        if not db.S_c.Connected then Exit;
        if db.Sql = nil then Exit;
        if db.Sql.Eof then Exit;
        if (Indx < 0) or (Indx >= db.Sql.Fields.Count) then Exit;
        RESULT := db.Sql.Fields[Indx].AsString;
    except on E: Exception do
           begin
                //Any_Exception(E);
           end;
    end;
end;

procedure DB_Setup_blob_param(
	Handle: Integer; X_Blob: Ref_obj;
          Index_blob: Integer );
var B: C_Blob;
    S: TBlobReader;
    db: TNATIVE_DB;
begin
    B :=  C_Blob(X_Blob.Obj);
    try
        S := TBlobReader.Create(B);
		{$IFDEF USE_LISTS_OF_DESCRIPTORS}
			db := TNATIVE_DB(All_db[Handle]);
		{$ELSE}
	    	db := TNATIVE_DB(Handle);
		{$ENDIF}
        if (db.S_c = nil) then Exit;
        try
        	{$IFDEF ODBC}
            db.Sql.ParamByName('@blob').DataType := ftBlob;
            db.Sql.ParamByName('@blob').ParamType := ptInput;
            db.Sql.ParamByName('@blob').LoadFromStream(S, ftBlob);
        	{$ELSE}
            db.Sql.Parameters.CreateParameter('@blob', ftBlob, pdInput, 0, '');
            db.Sql.Parameters.ParamByName('@blob').LoadFromStream(S, ftBlob);
            {$ENDIF}
        finally
            S.Free;
        end;
    except on  E: Exception do
               AL4.Any_exception(E);
    end;
end;

(*
/*

    
CONST STR:
    NATIVE_DB_import = "uses NATIVE_DB;"
    
    NATIVE_DB_Create_connection = @
    "   RESULT := DB_Create_connection(X_Connection, X_User, "
    "       X_Provider);"

    NATIVE_DB_Destroy_connection = @
    "   DB_Destroy_connection(X_Handle);"

    NATIVE_DB_Connect = @
    "   RESULT := DB_Connect(X_Handle, X_Password);"
    
    NATIVE_DB_Disconnect = @
    "   DB_Disconnect(X_handle);"

    NATIVE_DB_Is_connected = @
    "   RESULT := DB_Is_connected(X_handle);"
    
    NATIVE_DB_Begin_transaction = @
    "   DB_Begin_transaction(X_Handle);"

    NATIVE_DB_End_transaction = @
    "   DB_End_transaction(X_Handle, X_Commited);"

    NATIVE_DB_Commit_transaction = @
    ""

    NATIVE_DB_Rollback_transaction = @
    ""

    NATIVE_DB_Execute = @
    "   RESULT := DB_Execute(X_handle, X_SQL, X_blobs);"

    NATIVE_DB_Open = @
    "   RESULT := not DB_Open(X_handle, X_SQL);"

    NATIVE_DB_Close = @
    "   DB_Close(X_handle);"

    NATIVE_DB_Next = @
    "   RESULT := DB_Next(X_handle);"

    NATIVE_DB_Count_fields = @
    "   RESULT := DB_Count_fields(X_handle);"

    NATIVE_DB_Field_by_index = @
    "   RESULT := DB_Field_name_by_index(X_handle, X_Ind);"

    NATIVE_DB_Integer = @
    "   RESULT := DB_Integer(X_handle, X_Ind);"

    NATIVE_DB_Real = @
    "   RESULT := DB_Real(X_handle, X_Ind);"
    
    NATIVE_DB_Id = @
    "   NATIVE_DB.DB_Id(X_Handle, X_Ind, X_Value);"     

    NATIVE_DB_Date_time = @
    "   RESULT := DB_Date_time(X_handle, X_Ind);"

    NATIVE_DB_Boolean = @
    "   RESULT := DB_Boolean(X_handle, X_Ind);"

    NATIVE_DB_Is_null = @
    "   RESULT := DB_Is_null(X_handle, X_Ind);"

    NATIVE_DB_String = @
    "   RESULT := DB_String(X_handle, X_Ind);"

    NATIVE_Load_from_blob = ""

    NATIVE_Read_blob = ""
    
    .
    
*/
*)

end .

(*
/*
END
*/
*)



