{ $Id: PDOStatement.pas 23 2007-01-19 22:06:28Z jmarino $

############################################################################################

	Pascal Data Objects Library
	Copyright © 2006 John Marino, http://www.synsport.com
	Project site: http://pdo.sourceforge.net

############################################################################################

	This library is free software; you can redistribute it and/or
	modify it under the terms of the GNU Lesser General Public
	License as published by the Free Software Foundation; either
	version 2.1 of the License, or (at your option) any later version.

	This library is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
	Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public
	License along with this library; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

############################################################################################}


unit PDOStatement;

{$I directives.inc}

interface

uses
    Classes, Variants, PDOClasses, PDOCompatibility, SysUtils, PDOMessages;

type
    IPDOResult = interface;

    TPDORowKeyStrings     = TStringList;
    TPDOStatementType     = (DIRECT_STATEMENT, PREPARED_STATEMENT);

    TPDORowSetKeyStrings = class
        private
            FRows: Int64;
        public
            row: array of TStringList;
            procedure ClearRowSet;
            procedure InitializeRowSet (NumberRows: Int64);
            procedure BeforeDestruction; override;
            property  RowCount: Int64 Read FRows;
    end;

    TPDORowNative = class
        private
            hashlist: TStringList;
            FColumns: Byte;
        public
            column: array of IPDOResult;
            function hash (Key: Ansistring): IPDOResult;
            procedure InsertKey (HashIndex: Byte; Key: AnsiString);
            procedure Clearcolumns;
            procedure InitializeRow (NumberColumns: Byte);
            procedure BeforeDestruction; override;
            property  ColumnCount: Byte Read FColumns;
    end;

    TPDORowSetNative = class
        private
            FRows: Int64;
        public
            row: array of TPDORowNative;
            procedure ClearRowSet;
            procedure InitializeRowSet (NumberRows: Int64);
            procedure BeforeDestruction; override;
            property  RowCount: Int64 Read FRows;
    end;

    TPDOGenericTime = record
        year:        Cardinal;
        month:       Cardinal;
        day:         Cardinal;
        hour:        Cardinal;
        minute:      Cardinal;
        second:      Cardinal;
        neg:         Byte;
        second_part: Int64;
    end;

    TPDODataTypes = (
        integer_8,  integer_8_signed,
        integer_16, integer_16_signed,
        integer_32, integer_32_signed,
                    integer_64_signed, {int64signed supported by mysql, not delphi}
        float_32,   float_64,
        string_1,   string_unlimited,
        generic_time, byte_buffer      {last must be as big as maxBLOBSize}
    );

    IPDOStatement = interface(IInterface)
    ['{39E14D61-7516-4619-8726-2961416E00C2}']
        procedure setSQL  (SQL: AnsiString; StatementType: TPDOStatementType);

        procedure bindValue  (valueIndex: Cardinal;   PassedValue: Variant); overload;
        procedure bindValue  (valueIndex: AnsiString; PassedValue: Variant); overload;
        procedure bindTimeValue  (valueIndex: Cardinal;   PassedValue: TPDOGenericTime); overload;
        procedure bindTimeValue  (valueIndex: AnsiString; PassedValue: TPDOGenericTime); overload;

        procedure bindColumn (columnIndex: Cardinal;   variableAddress: Pointer); overload;
        procedure bindColumn (columnIndex: Cardinal;   variableAddress: Pointer; TypeOverride: TPDODataTypes); overload;
        procedure bindColumn (columnIndex: AnsiString; variableAddress: Pointer); overload;
        procedure bindColumn (columnIndex: AnsiString; variableAddress: Pointer; TypeOverride: TPDODataTypes); overload;

        function closeCursor: boolean;
        function columnCount: Integer;
        function ErrorCode: AnsiString;
        function ErrorInfo: PDO_errorInfoRecord;

        function execute: Boolean; overload;
        function execute (DelimitedBind: AnsiString): Boolean; overload;

        function GetRowsAffected: Int64;
        function GetNumberRows: Int64;
        function LastInsertId: Int64;
        function nextRowSet: Boolean;

        function fetch_bound: Boolean;
        function fetch (var row: TPDORowKeyStrings): Boolean; overload;
        function fetch (var row: TPDORowNative): Boolean; overload;
        function fetch_all (var rowset: TPDORowSetKeyStrings): Boolean; overload;
        function fetch_all (var rowset: TPDORowSetNative): Boolean; overload;
    end;

    IPDOResult = interface(IInterface)
    ['{395692A4-4149-44E1-A58B-1A30DAACFEB3}']
        function getValue:        Variant;
        function getNull:         Boolean;
        property value:           Variant READ getValue;
        property null:            Boolean READ getNull;
        function asString:        AnsiString;
        function asUnicodeString: WideString;
        function asPChar:         PChar;
        function asByte:          Byte;
        function asShortInt:      ShortInt;
        function asWord:          Word;
        function asSmallInt:      SmallInt;
        function asLongWord:      LongWord;
        function asCardinal:      Cardinal;
        function asLongInt:       LongInt;
        function asInteger:       Integer;
        function asInt64:         Int64;
        function asSingle:        Single;
        function asDouble:        Double;
        function asExtended:      Extended;
        function asBoolean:       Boolean;
        function asDate:          TDateTime;
        function asTime:          TDateTime;
        function asTimestamp:     TDateTime;
        function asAsciiStream:   TStream;
        function asBytes:         TByteDynArray;
    end;


implementation

procedure TPDORowSetKeyStrings.ClearRowSet;
Var
    loop: Int64;
Begin
    loop := Length(self.row);
    while (loop > 0) do
    begin
        loop := loop - 1;
        self.row[loop].Destroy;
    end;
    SetLength(self.row,0);
End;

procedure TPDORowSetKeyStrings.InitializeRowSet(NumberRows: Int64);
var
    Loop: Int64;
Begin
    SetLength(self.row,NumberRows);
    self.FRows := NumberRows;
    loop := 0;
    while (loop < NumberRows) do
    Begin
        self.row[loop] := TStringlist.Create;
        loop := loop + 1;
    End;
End;

procedure TPDORowSetKeyStrings.BeforeDestruction;
Begin
    self.ClearRowSet;
End;

procedure TPDORowNative.Clearcolumns;
Begin
    SetLength(self.column,0);
    self.FColumns := 0;
End;

procedure TPDORowNative.InitializeRow(NumberColumns: Byte);
Begin
    SetLength(self.column,NumberColumns);
    if assigned(self.hashlist) then
        self.hashlist.Clear
    else
        self.hashlist := TStringlist.Create;
    self.FColumns := numberColumns;
End;

procedure TPDORowNative.BeforeDestruction;
Begin
    self.Clearcolumns;
    self.hashlist.Free;
End;

procedure TPDORowNative.InsertKey (HashIndex: Byte; Key: AnsiString);
var
    localIndex: SmallInt;
    Keystring: AnsiString;
Begin
    localIndex := self.hashlist.IndexOfName(Key);
    if (localIndex = -1) then
        begin
            Keystring := Key + '=' + IntToStr(HashIndex);
            self.hashlist.Add(Keystring);
        end;
End;

function TPDORowNative.hash (Key: Ansistring): IPDOResult;
var
    localIndex: SmallInt;
    hashIndex: Byte;
Begin
    localIndex := self.hashlist.IndexOfName(Key);
    if (localIndex = -1) then
    begin
        raise Exception.CreateFmt(SBoundVarStrIndexMissing,[key]);
        exit;
    end;
    hashIndex := StrToInt(self.hashlist.ValueFromIndex[localIndex]);
    Result := self.column [hashIndex];
End;

procedure TPDORowSetNative.InitializeRowSet (NumberRows: Int64);
var
    Loop: Int64;
Begin
    SetLength(self.row,NumberRows);
    self.FRows := NumberRows;
    loop := 0;
    while (loop < NumberRows) do
    Begin
        self.row[loop] := TPDORowNative.Create;
        loop := loop + 1;
    End;
End;

procedure TPDORowSetNative.ClearRowSet;
Var
    loop: Int64;
Begin
    loop := Length(self.row);
    while (loop > 0) do
    begin
        loop := loop - 1;
        self.row[loop].Destroy;
    end;
    SetLength(self.row,0);
    self.FRows := 0;
End;

procedure TPDORowSetNative.BeforeDestruction;
Begin
    self.ClearRowSet;
End;

End.
