disqlite3dataset.pas

来自「DELPHI 访问SQLITE3 数据库的VCL控件」· PAS 代码 · 共 1,786 行 · 第 1/4 页

PAS
1,786
字号
{-------------------------------------------------------------------------------
 
 Copyright (c) 1999-2007 Ralf Junker, The Delphi Inspiration
 Internet: http://www.yunqa.de/delphi/
 E-Mail:   delphi@yunqa.de

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

unit DISQLite3DataSet;

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

interface

uses
  Classes, DB,
  DISQLite3Database;

type

  TDISQLite3Column = packed record
    ColumnName: WideString;
    ColumnType: Integer;
    ColumnDeclaration: WideString;
    ColumnOriginName: WideString;
    ColumnTableName: WideString;
    ColumnDatabaseName: WideString;
    ColumnIsKey: Boolean;
  end;

  TDISQLite3Data = packed record
    Col: TDISQLite3Column;
    Data: TDISQLite3Cell16;
  end;

  TDISQLite3Row = array[0..(MaxInt - SizeOf(TDISQLite3Data)) div SizeOf(TDISQLite3Data) - 1] of TDISQLite3Data;

  PDISQLite3Row = ^TDISQLite3Row;

  TDISQLite3InitFieldDefEvent = procedure(
    const AColumn: TDISQLite3Column;
    const AFieldDef: TFieldDef) of object;

  TDISqlite3UniDirQuery = class({$IFDEF COMPILER_10_UP}TWideDataSet{$ELSE}TDataSet{$ENDIF})
  private

    FColumnCount: Integer;

    FRowBuffer: PDISQLite3Row;

    FSelectStatement: TDISQLite3Statement;

    FUpdateStatements: array[TUpdateKind] of TDISQLite3Statement;

    FOnInitFieldDef: TDISQLite3InitFieldDefEvent;

    function GetDatabase: TDISQLite3Database;

    function GetSelectSQL: WideString;

    function GetUpdateSql(const AUpdateKind: TUpdateKind): WideString;

    procedure SetDatabase(const AValue: TDISQLite3Database);

    procedure SelectStatementAfterClose(ASender: TObject);

    procedure SetSelectSQL(const AValue: WideString);

    procedure SetUpdateSql(const AUpdateKind: TUpdateKind; const AValue: WideString);

  protected

    {$IFNDEF COMPILER_6_UP}

    function AllocRecordBuffer: PChar; override;

    procedure FreeRecordBuffer(var Buffer: PChar); override;

    procedure GetBookmarkData(Buffer: PChar; Data: Pointer); override;

    function GetBookmarkFlag(Buffer: PChar): TBookmarkFlag; override;

    function GetRecordSize: Word; override;

    procedure InternalAddRecord(Buffer: Pointer; Append: Boolean); override;

    procedure InternalDelete; override;

    procedure InternalFirst; override;

    procedure InternalGotoBookmark(Bookmark: Pointer); override;

    procedure InternalInitRecord(Buffer: PChar); override;

    procedure InternalLast; override;

    procedure InternalPost; override;

    procedure InternalSetToRecord(Buffer: PChar); override;

    procedure SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag); override;

    procedure SetBookmarkData(Buffer: PChar; Data: Pointer); override;

    procedure SetFieldData(Field: TField; Buffer: Pointer); override;
    {$ENDIF !COMPILER_6_UP}

    procedure AllocRowBuffer(
      const AColumnCount: Integer);

    procedure DoInitFieldDef(
      const AColumn: TDISQLite3Column;
      const AFieldDef: TFieldDef); virtual;

    procedure FreeRowBuffer;

    function GetCanModify: Boolean; override;

    {$IFNDEF COMPILER_5_UP}

    function GetFieldClass(
      AFieldType: TFieldType): TFieldClass; override;
    {$ENDIF !COMPILER_5_UP}

    function GetRecord(Buffer: PAnsiChar; GetMode: TGetMode; DoCheck: Boolean): TGetResult; override;

    procedure InternalClose; override;

    procedure InternalHandleException; override;

    procedure InternalInitFieldDefs; override;

    procedure InternalOpen; override;

    function IsCursorOpen: Boolean; override;

    {$IFDEF COMPILER_5_UP}

    procedure PSEndTransaction(
      Commit: Boolean); override;

    function PSExecuteStatement(
      const ASQL: {$IFDEF COMPILER_10_UP}WideString{$ELSE}AnsiString{$ENDIF};
      AParams: TParams;
      AResultSet: Pointer = nil): Integer; override;

    {$IFDEF COMPILER_10_UP}

    function PSGetKeyFieldsW: WideString; override;
    {$ELSE COMPILER_10_UP}

    function PSGetKeyFields: AnsiString; override;
    {$ENDIF COMPILER_10_UP}

    {$IFDEF COMPILER_10_UP}

    function PSGetQuoteCharW: WideString; override;
    {$ELSE COMPILER_10_UP}

    function PSGetQuoteChar: AnsiString; override;
    {$ENDIF COMPILER_10_UP}

    {$IFDEF COMPILER_10_UP}

    function PSGetTableNameW: WideString; override;
    {$ELSE COMPILER_10_UP}

    function PSGetTableName: AnsiString; override;
    {$ENDIF COMPILER_10_UP}

    function PSInTransaction: Boolean; override;

    function PSIsSQLBased: Boolean; override;

    function PSIsSQLSupported: Boolean; override;

    procedure PSReset; override;

    procedure PSStartTransaction; override;

    function PSUpdateRecord(
      AUpdateKind: TUpdateKind;
      aDelta: TDataSet): Boolean; override;

    {$ENDIF COMPILER_5_UP}

  public

    constructor Create(AOwner: TComponent); override;

    destructor Destroy; override;

    function CreateBlobStream(
      Field: TField;
      Mode: TBlobStreamMode): TStream; override;

    function GetFieldData(
      Field: TField;
      Buffer: Pointer): Boolean; overload; override;

    {$IFDEF COMPILER_5_UP}

    function GetFieldData(
      Field: TField;
      Buffer: Pointer;
      NativeFormat: Boolean): Boolean; overload; override;
    {$ENDIF COMPILER_5_UP}

    {$IFDEF COMPILER_6_UP}

    function IsSequenced: Boolean; override;
    {$ENDIF COMPILER_6_UP}

  published

    property Database: TDISQLite3Database read GetDatabase write SetDatabase;

    property DeleteSQL: WideString index ukDelete read GetUpdateSql write SetUpdateSql;

    property InsertSQL: WideString index ukInsert read GetUpdateSql write SetUpdateSql;

    property ModifySQL: WideString index ukModify read GetUpdateSql write SetUpdateSql;

    property SelectSQL: WideString read GetSelectSQL write SetSelectSQL;

    property OnInitFieldDef: TDISQLite3InitFieldDefEvent read FOnInitFieldDef write FOnInitFieldDef;

    property Active;

    property BeforeOpen;

    property AfterOpen;

    property BeforeClose;

    property AfterClose;

    property BeforeScroll;

    property AfterScroll;
    {$IFDEF COMPILER_5_UP}

    property BeforeRefresh;

    property AfterRefresh;
    {$ENDIF COMPILER_5_UP}
  end;

  TDISQLite3BlobStream = class(TCustomMemoryStream)
  public

    constructor Create(const Data: Pointer; const Size: Integer);

    function Write(const Buffer; Count: Integer): Integer; override;
  end;

  TDISQLite3MemoStream = class(TStringStream)
  public

    function Write(const Buffer; Count: Integer): Integer; override;
  end;

  TDISQLite3WideMemoStream = class(TDISQLite3BlobStream)
  end;

  {$IFNDEF COMPILER_10_UP}

  TDISQLite3BlobField = class(TBlobField)
  protected

    function GetAsWideString: WideString;

    procedure SetAsWideString(const AValue: WideString);
  end;
  {$ENDIF !COMPILER_10_UP}

  TDISQLite3MemoField = class({$IFDEF COMPILER_10_UP}TBlobField{$ELSE}TDISQLite3BlobField{$ENDIF})
  protected

    function GetAsString: AnsiString; override;

    procedure SetAsString(const AValue: AnsiString); override;
  public

    constructor Create(AOwner: TComponent); override;
  end;

  TDISQLite3WideMemoField = class({$IFDEF COMPILER_10_UP}TWideMemoField{$ELSE}TDISQLite3BlobField{$ENDIF})
    {$IFNDEF COMPILER_10_UP}
  protected

    function GetAsString: string; override;

    procedure SetAsString(const Value: string); override;
  public

    constructor Create(AOwner: TComponent); override;

    property Value: WideString read GetAsWideString write SetAsWideString;
    {$ENDIF !COMPILER_10_UP}
  end;

  TDISQLite3WideStringField = class({$IFDEF COMPILER_5_UP}TWideStringField{$ELSE}TStringField{$ENDIF})
  protected
    {$IFNDEF COMPILER_10_UP}

    function GetAsWideString: WideString;
    {$ENDIF !COMPILER_10_UP}
    {$IFNDEF COMPILER_5_UP}

    class procedure CheckTypeSize(Value: Integer); override;

    function GetAsString: string; override;

    function GetAsVariant: Variant; override;

    function GetDataSize: {$IFDEF COMPILER_6_UP}Integer{$ELSE}Word{$ENDIF}; override;

    procedure SetAsString(const Value: string); override;

    procedure SetVarValue(const Value: Variant); override;

    procedure SetAsWideString(const AValue: WideString); {$IFDEF COMPILER_10_UP} override; {$ENDIF}
  public

    constructor Create(AOwner: TComponent); override;

    property Value: WideString read GetAsWideString write SetAsWideString;
    {$ENDIF !COMPILER_5_UP}
  end;

  TDISQLite3DataSetImporter = class(TComponent)
  private
    FDatabase: TDISQLite3Database;
    FDataSet: TDataSet;
    FTableName: WideString;
    procedure SetDatabase(const AValue: TDISQLite3Database);
    procedure SetDataSet(const AValue: TDataSet);
  protected

    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  public

    procedure Execute;
  published

    property Database: TDISQLite3Database read FDatabase write SetDatabase;

    property DataSet: TDataSet read FDataSet write SetDataSet;

    property TableName: WideString read FTableName write FTableName;
  end;

resourcestring

  SUpdateFailed = 'Update failed';
  {$IFNDEF COMPILER_6_UP}

  SDataSetUnidirectional = 'Operation not allowed on a unidirectional dataset';
  {$ENDIF !COMPILER_6_UP}

implementation

uses
  Windows, {$IFDEF COMPILER_6_UP}RTLConsts, Variants{$ELSE}Consts, Forms{$ENDIF},
  DBConsts, SysUtils,
  DISQLite3Api;

constructor TDISqlite3UniDirQuery.Create;
begin
  inherited;
  {$IFDEF COMPILER_6_UP}
  SetUniDirectional(True);
  {$ENDIF COMPILER_6_UP}
  FSelectStatement := TDISQLite3Statement.Create;
  FSelectStatement.AfterClose := SelectStatementAfterClose;
end;

destructor TDISqlite3UniDirQuery.Destroy;
begin
  FSelectStatement.Free;
  inherited;
end;

procedure TDISqlite3UniDirQuery.AllocRowBuffer(const AColumnCount: Integer);
begin
  FRowBuffer := AllocMem(AColumnCount * SizeOf(FRowBuffer[0]));
  FColumnCount := AColumnCount;
end;

function TDISqlite3UniDirQuery.CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream;
var
  l: Integer;
  s: AnsiString;
begin
  if Assigned(FRowBuffer) then
    with FRowBuffer^[Field.FieldNo - 1] do
      case Field.DataType of
        ftMemo:

          if Data.CellType = SQLITE_TEXT then
            begin

              l := WideCharToMultiByte(CP_ACP, 0, Data.CellText.p, Data.CellText.l, nil, 0, nil, nil);
              SetLength(s, l);
              WideCharToMultiByte(CP_ACP, 0, Data.CellText.p, Data.CellText.l, PAnsiChar(s), l, nil, nil);
              Result := TDISQLite3MemoStream.Create(s);
              Exit;
            end;

        {$IFDEF COMPILER_10_UP}
        ftWideMemo:
          if Data.CellType = SQLITE_TEXT then
            begin
              Result := TDISQLite3WideMemoStream.Create(Data.CellBlob.p, Data.CellBlob.l * 2);
              Exit;
            end;
        {$ENDIF COMPILER_10_UP}

        else
          if Data.CellType = SQLITE_BLOB then
            begin
              Result := TDISQLite3BlobStream.Create(Data.CellBlob.p, Data.CellBlob.l);
              Exit;
            end;
      end;

  Result := TDISQLite3BlobStream.Create(nil, 0);
end;

procedure TDISqlite3UniDirQuery.DoInitFieldDef(
  const AColumn: TDISQLite3Column;
  const AFieldDef: TFieldDef);
begin
  if Assigned(FOnInitFieldDef) then
    FOnInitFieldDef(AColumn, AFieldDef);
end;

procedure TDISqlite3UniDirQuery.FreeRowBuffer;
var
  i: Integer;
begin
  for i := 0 to FColumnCount - 1 do
    with FRowBuffer^[i] do
      begin
        Col.ColumnName := '';

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?