disqlite3dataset.pas

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

PAS
1,786
字号
        Col.ColumnDeclaration := '';
        Col.ColumnOriginName := '';
        Col.ColumnTableName := '';
        Col.ColumnDatabaseName := '';

        sqlite3_finalize_cell16(Data);
      end;

  FreeMem(FRowBuffer);
  FRowBuffer := nil;
  FColumnCount := 0;
end;

function TDISqlite3UniDirQuery.GetUpdateSql(const AUpdateKind: TUpdateKind): WideString;
var
  Stmt: TDISQLite3Statement;
begin
  Stmt := FUpdateStatements[AUpdateKind];
  if Assigned(Stmt) then
    Result := Stmt.SQL16
  else
    Result := '';
end;

function TDISqlite3UniDirQuery.GetSelectSQL: WideString;
begin
  Result := FSelectStatement.SQL16;
end;

procedure TDISqlite3UniDirQuery.SetUpdateSql(const AUpdateKind: TUpdateKind; const AValue: WideString);
var
  Stmt: TDISQLite3Statement;
begin
  Stmt := FUpdateStatements[AUpdateKind];
  if Assigned(Stmt) then
    if AValue <> '' then
      begin
        Stmt.Active := False;
        Stmt.SQL16 := AValue;
      end
    else
      begin
        FUpdateStatements[AUpdateKind] := nil;
        Stmt.Free;
      end
  else
    if AValue <> '' then
      begin
        Stmt := TDISQLite3Statement.Create;
        Stmt.SQL16 := AValue;
        Stmt.Database := Database;
        FUpdateStatements[AUpdateKind] := Stmt;
      end;
end;

procedure TDISqlite3UniDirQuery.SetSelectSQL(const AValue: WideString);
begin
  FSelectStatement.SQL16 := AValue;
end;

procedure TDISqlite3UniDirQuery.InternalOpen;
begin
  FSelectStatement.Active := True;
  InternalInitFieldDefs;
  if DefaultFields then
    CreateFields;
  BindFields(True);
end;

procedure TDISqlite3UniDirQuery.InternalClose;
var
  uk: TUpdateKind;
  Stmt: TDISQLite3Statement;
begin
  FSelectStatement.Active := False;
  for uk := Low(TUpdateKind) to High(TUpdateKind) do
    begin
      Stmt := FUpdateStatements[uk];
      if Assigned(Stmt) then
        Stmt.Active := False;
    end;

  FreeRowBuffer;

  if DefaultFields then
    DestroyFields;
end;

function TDISqlite3UniDirQuery.IsCursorOpen: Boolean;
begin
  Result := FSelectStatement.Active;
end;

procedure TDISqlite3UniDirQuery.InternalInitFieldDefs;

  function IsKey(
    const ADatabaseName: WideString;
    const ATableName: WideString;
    const AOriginName: WideString): Boolean;
  var
    SQL: WideString;
    Stmt, Stmt2: TDISQLite3Statement;
  begin
    Result :=
      (ADatabaseName <> '') and
      (ATableName <> '') and
      (AOriginName <> '');
    if not Result then Exit;

    Result := AOriginName = 'rowid';
    if Result then Exit;

    Stmt := TDISQLite3Statement.Create;
    Stmt.Database := Database;
    try
      Stmt.SQL16 := sqlite3_pragma_database16(ADatabaseName) + '"table_info"(' + DISQLite3Api.QuotedStr16(ATableName) + ')';
      Stmt.Active := True;
      try
        while Stmt.Step = SQLITE_ROW do
          begin
            Result :=
              (Stmt.Column_Str16(1) = AOriginName) and
            (Stmt.Column_Int(5) = 1);
            if Result then Break;
          end;
      finally
        Stmt.Active := False;
      end;

      if not Result then
        begin
          SQL := sqlite3_pragma_database16(ADatabaseName) + '"index_list"(' + DISQLite3Api.QuotedStr16(ATableName) + ')';
          Stmt.SQL16 := SQL;
          Stmt.Active := True;

          Stmt2 := TDISQLite3Statement.Create;
          Stmt2.Database := Database;
          try
            while Stmt.Step = SQLITE_ROW do
              if Stmt.Column_Int(2) = 1 then
                begin
                  SQL := sqlite3_pragma_database16(ADatabaseName) + '"index_info"(' + DISQLite3Api.QuotedStr16(Stmt.Column_Str16(1)) + ')';
                  Stmt2.Close;
                  Stmt2.SQL16 := SQL;
                  Stmt2.Open;
                  while Stmt2.Step = SQLITE_ROW do
                    begin
                      Result := Stmt2.Column_Str16(2) = AOriginName;
                      if Result then Break;
                    end;
                  if Result then Break;
                end;
          finally
            Stmt2.Free;
          end;
        end;
    finally
      Stmt.Free;
    end;

  end;

var
  ColumnIdx, i, t: Integer;
  f: TField;
  FDataType: TFieldType;
  FSize: Integer;
  ColumnDeclaration, FieldName, UniqueFieldName: WideString;
  NewFieldDef: TFieldDef;
  Stepped, StepResult: Boolean;
  Stmt: TDISQLite3Statement;
begin
  FieldDefs.Clear;

  if not Assigned(FRowBuffer) then
    begin
      Stmt := TDISQLite3Statement.Create;
      try
        Stmt.Assign(FSelectStatement);
        Stmt.Active := True;

        Stepped := False; StepResult := False;

        AllocRowBuffer(Stmt.Column_Count);

        for ColumnIdx := 0 to FColumnCount - 1 do
          begin

            ColumnDeclaration := Stmt.Column_DeclType16(ColumnIdx);
            if ColumnDeclaration <> '' then
              begin
                t := SQLITE3_AFFINITY_TO_TYPE[sqlite3_affinity16(ColumnDeclaration)];
              end
            else
              begin
                if not Stepped then
                  begin
                    Stepped := True;
                    try
                      StepResult := Stmt.Step = SQLITE_ROW;
                    except
                      StepResult := False;
                    end;
                  end;
                if StepResult then
                  begin
                    t := Stmt.Column_Type(ColumnIdx);

                    if t = SQLITE_NULL then
                      t := SQLITE_TEXT;
                  end
                else
                  t := SQLITE_TEXT;
              end;

            with FRowBuffer^[ColumnIdx] do
              begin
                Col.ColumnName := Stmt.Column_Name16(ColumnIdx);
                Col.ColumnType := t;
                Col.ColumnDeclaration := ColumnDeclaration;
                Col.ColumnOriginName := Stmt.Column_Origin_Name16(ColumnIdx);
                Col.ColumnTableName := Stmt.Column_Table_Name16(ColumnIdx);
                Col.ColumnDatabaseName := Stmt.Column_database_Name16(ColumnIdx);
                Col.ColumnIsKey := IsKey(Col.ColumnDatabaseName, Col.ColumnTableName, Col.ColumnOriginName);
              end;
          end;

      finally
        Stmt.Free;
      end;
    end;

  for ColumnIdx := 0 to FColumnCount - 1 do
    with FRowBuffer^[ColumnIdx] do
      begin

        i := 0;
        FieldName := Col.ColumnName;
        UniqueFieldName := FieldName;
        while FieldDefs.IndexOf(UniqueFieldName) >= 0 do
          begin
            Inc(i);
            UniqueFieldName := Format('%s_%d', [FieldName, i]);
          end;

        f := FindField(UniqueFieldName);
        if Assigned(f) then
          begin
            FDataType := f.DataType;
            FSize := f.Size;
          end
        else
          begin
            FSize := 0;
            case Col.ColumnType of
              SQLITE_INTEGER:
                begin
                  FDataType := ftLargeInt;
                end;
              SQLITE_FLOAT:
                begin
                  FDataType := ftFloat;
                end;
              SQLITE_BLOB:
                begin
                  FDataType := ftBlob;
                end;
              SQLITE_TEXT:
                begin
                  FDataType := ftWideString;
                  FSize := 20;
                end;
              else
                Assert(False, 'Invalid ColumnType');
                FDataType := ftUnknown;
            end;
          end;

        NewFieldDef := FieldDefs.AddFieldDef;
        try
          NewFieldDef.Name := UniqueFieldName;
          NewFieldDef.DataType := FDataType;

          if FSize <> 0 then
            NewFieldDef.Size := FSize;
          DoInitFieldDef(Col, NewFieldDef);
        except
          NewFieldDef.Free;
          raise;
        end;
      end;
end;

procedure TDISqlite3UniDirQuery.InternalHandleException;
begin
  {$IFDEF COMPILER_6_UP}
  if Assigned(Classes.ApplicationHandleException) then
    Classes.ApplicationHandleException(Self);
  {$ELSE COMPILER_6_UP}
  Application.HandleException(Self);
  {$ENDIF COMPILER_6_UP}
end;

{$IFDEF COMPILER_6_UP}
function TDISqlite3UniDirQuery.IsSequenced: Boolean;
begin
  Result := False;
end;
{$ENDIF COMPILER_6_UP}

function TDISqlite3UniDirQuery.GetCanModify: Boolean;
begin
  Result := False;
end;

{$IFNDEF COMPILER_5_UP}
function TDISqlite3UniDirQuery.GetFieldClass(AFieldType: TFieldType): TFieldClass;
begin
  Result := inherited GetFieldClass(AFieldType);
  if not Assigned(Result) and (AFieldType = ftWideString) then
    Result := TDISQLite3WideStringField;
end;
{$ENDIF !COMPILER_5_UP}

function TDISqlite3UniDirQuery.GetDatabase: TDISQLite3Database;
begin
  Result := FSelectStatement.Database;
end;

function TDISqlite3UniDirQuery.GetRecord(Buffer: PAnsiChar; GetMode: TGetMode; DoCheck: Boolean): TGetResult;
var
  i: Integer;
begin
  case GetMode of
    gmNext:
      case FSelectStatement.Step of
        SQLITE_ROW:
          begin
            for i := 0 to FColumnCount - 1 do
              with FRowBuffer^[i] do
                begin
                  sqlite3_finalize_cell16(Data);
                  FSelectStatement.column_cell16(i, Data);
                end;

            Result := grOK;
            Exit;
          end;
        SQLITE_DONE:
          begin
            Result := grEOF;
            Exit;
          end;
      end;
    gmCurrent:
      begin
        Result := grOK;
        Exit;
      end;
    {$IFNDEF COMPILER_6_UP}

    gmPrior:
      begin
        DatabaseError(PResStringRec(@SDataSetUnidirectional), Self);
      end;
    {$ENDIF !COMPILER_6_UP}
  end;
  Result := grError;
end;

function TDISqlite3UniDirQuery.GetFieldData(Field: TField; Buffer: Pointer): Boolean;
var
  ColumnIdx: Integer;
  l: Integer;
  s: AnsiString;
  {$IFDEF COMPILER_10_UP}
  w: WideString;
  {$ENDIF COMPILER_10_UP}
begin
  Result := Assigned(FRowBuffer);
  if not Result then Exit;

  ColumnIdx := Field.FieldNo - 1;
  Result := ColumnIdx >= 0;
  if not Result then Exit;

  with FRowBuffer^[ColumnIdx] do
    begin

      Result := Data.CellType <> SQLITE_NULL;
      if not Result then Exit;

      if Assigned(Buffer) then
        case Field.DataType of

          ftBlob, ftMemo, ftGraphic, ftFmtMemo:
            begin

            end;

          ftDate:
            begin
              {$IFDEF COMPILER_5_UP}
              PDateTime(Buffer)^ := sqlite3_cell16_as_date(Data);
              {$ELSE COMPILER_5_UP}
              PInteger(Buffer)^ := DateTimeToTimeStamp(sqlite3_cell16_as_datetime(Data)).Date;
              {$ENDIF COMPILER_5_UP}
            end;

          ftTime:
            begin
              {$IFDEF COMPILER_5_UP}
              PDateTime(Buffer)^ := sqlite3_cell16_as_time(Data);
              {$ELSE COMPILER_5_UP}
              PInteger(Buffer)^ := DateTimeToTimeStamp(sqlite3_cell16_as_datetime(Data)).Time;
              {$ENDIF COMPILER_5_UP}
            end;

          ftDateTime
            {$IFDEF COMPILER_6_UP}, ftTimestamp{$ENDIF}
          {$IFDEF COMPILER_10_UP}, ftOraTimeStamp{$ENDIF}:
            begin
              {$IFDEF COMPILER_5_UP}
              PDateTime(Buffer)^ := sqlite3_cell16_as_datetime(Data);
              {$ELSE COMPILER_5_UP}
              PDouble(Buffer)^ := TimeStampToMSecs(DateTimeToTimeStamp(sqlite3_cell16_as_datetime(Data)));
              {$ENDIF COMPILER_5_UP}
            end;

          ftInteger:
            begin
              PInteger(Buffer)^ := sqlite3_cell16_as_integer(Data);
            end;

          ftLargeInt:
            begin
              PInt64(Buffer)^ := sqlite3_cell16_as_int64(Data);
            end;

          ftFloat, ftCurrency:
            begin
              PDouble(Buffer)^ := sqlite3_cell16_as_float(Data);
            end;

          ftString:
            begin
              s := sqlite3_cell16_as_ansistring(Data);

⌨️ 快捷键说明

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