myservicesuni.pas

来自「CrLab UniDAC 1.0 include sources」· PAS 代码 · 共 1,295 行 · 第 1/3 页

PAS
1,295
字号
      Limit := FLimit;
    Result := Result + ' LIMIT ' + IntToStr(FOffset) + ', ' + IntToStr(Limit);

    if BatchedHandler then begin
      Result := Result + ';';
      Result := Result + ' HANDLER ' + QTableName + ' CLOSE';
    end;
  end;
end;

{ TCustomMyDataSetUpdater }

constructor TCustomMyDataSetUpdater.Create(AOwner: TDataSetService);
begin
  inherited;

  FDataSetService := TCustomMyDataSetService(AOwner);
end;

function TCustomMyDataSetUpdater.GetIdentityFieldValue(var Value: variant): boolean;
var
  v: variant;
  id: int64;
begin
  Result := False;
  BeginConnection;
  try
    FDataSetService.GetIConnection.GetProp(prLastInsertId, v);
  {$IFDEF VER6P}
    id := v;
  {$ELSE}
    id := PInt64(@TVarData(v).VInteger)^;
  {$ENDIF}
    if id <> 0 then begin
    {$IFDEF VER6P}
      Value := id;
    {$ELSE}
      Value := Integer(id); // Int64 not supported if Delphi5 variants
    {$ENDIF}
      Result := True;
    end;
  finally
    EndConnection;
  end;
end;

procedure TCustomMyDataSetUpdater.CheckUpdateQuery(const StatementType: TStatementType);
begin
  inherited;

  if FUpdateQuery is TCustomDADataSet then begin
    TDBAccessUtils.SetFetchAll(TCustomDADataSet(FUpdateQuery), True);
  end;
end;

procedure TCustomMyDataSetUpdater.SetUpdateQueryOptions(const StatementType: TStatementType);
var
  DestRecordSet, SourceRecordSet: TCRRecordSet;

  procedure CopyPropR(Prop: integer);
  var
    v: variant;
  begin
    SourceRecordSet.GetProp(Prop, v);
    DestRecordSet.SetProp(Prop, v);
  end;

begin
  SourceRecordSet := GetIRecordSet;
  DestRecordSet := TDBAccessUtils.GetIRecordSet(FUpdateQuery as TCustomDADataSet);

  CopyPropR(prEnableBoolean);
end;

procedure TCustomMyDataSetUpdater.CheckUpdateSQL(const SQL: string;
  const StatementTypes: TStatementTypes; out ParamsInfo: TDAParamsInfo; UseGenerator: boolean = True);
var
  Offset, i: integer;
  ICommand: TMySQLCommand;
begin
  inherited;

  if ParamsInfo = nil then
    Exit;

  if not (((FDataSet.Params.Count > 0) or FDataSetService.IsFullRefresh) and (stRefresh in StatementTypes)) and not (stRefreshQuick in StatementTypes) then begin
    if IsClass(FUpdateQuery, TCustomDADataSet) then
      ICommand := TDBAccessUtils.GetICommand(TCustomDADataSet(FUpdateQuery)) as TMySQLCommand
    else
    if IsClass(FUpdateQuery, TCustomDASQL) then
      ICommand := TDBAccessUtils.GetICommand(TCustomDASQL(FUpdateQuery)) as TMySQLCommand
    else begin
      ICommand := nil;
      Assert(False);
    end;

    for i := 0 to ParamsInfo.Count - 1 do begin
      Offset := TCustomMySQLGenerator(FDataSetService.SQLGenerator).GetParamOffset(i);
      ICommand.SetProp(prParamPosition, Offset);
    end;
  end;
end;

function TCustomMyDataSetUpdater.IsRefreshQuickField(FieldDesc: TFieldDesc): boolean;
begin
  Result := TMySQLFieldDesc(FieldDesc).MySQLType = FIELD_TYPE_TIMESTAMP;
end;

procedure TCustomMyDataSetUpdater.SaveMaxRefreshQuickValue(FieldDesc: TFieldDesc; const Value: variant);
var
  Field: TMySQLFieldDesc;
  CurrValue: TDateTime;
begin
  CurrValue := 0;
  if (not VarIsEmpty(Value)) and (not VarIsNull(Value)) then
    CurrValue := Value;
  Field := TMySQLFieldDesc(GetIRecordSet.FindField(FieldDesc.Name));
  if (Field <> nil) and (Field.MySQLType = FIELD_TYPE_TIMESTAMP) and (Field.TableInfo <> nil) then begin
    if TMyTableInfo(Field.TableInfo).MaxTimestamp < CurrValue then
      TMyTableInfo(Field.TableInfo).MaxTimestamp := CurrValue;
  end;
end;

procedure TCustomMyDataSetUpdater.PrepareUpdate;
begin
  if roBeforeEdit in FDataSet.RefreshOptions then
    PerformRefreshRecord;

  inherited;
end;

function TCustomMyDataSetUpdater.PerformLock: boolean;
begin
  if not TDBAccessUtils.GetFetchAll(FDataSet) then
    DatabaseError(SLockVsFetchAll);

  Result := inherited PerformLock;
end;

{ TCustomMyDataSetService }

constructor TCustomMyDataSetService.Create(AOwner: TMemDataSet);
begin
  inherited;

  FLeftQuote := '`';
  FRightQuote := '`';
end;

procedure TCustomMyDataSetService.CreateDataSetUpdater;
begin
  SetDataSetUpdater(TCustomMyDataSetUpdater.Create(Self));
end;

procedure TCustomMyDataSetService.SetDataSetUpdater(Value: TDataSetUpdater);
begin
  inherited;

  FUpdater := TCustomMyDataSetUpdater(Value);
end;

procedure TCustomMyDataSetService.CreateSQLGenerator;
begin
  SetSQLGenerator(TCustomMySQLGenerator.Create(Self));
end;

function TCustomMyDataSetService.DetectCanModify: boolean;
begin
  Assert(GetIRecordSet <> nil, 'FIRecordSet must be setted to this time');

  Result := inherited DetectCanModify or
    not (FDataSet.ReadOnly or FDataSet.UniDirectional) and
    (FIsAnyFieldCanBeModified or
    (FDataSet.SQLInsert.Count > 0) or
    (FDataSet.SQLUpdate.Count > 0) or
    (FDataSet.SQLDelete.Count > 0));
end;

function TCustomMyDataSetService.CanUseAllKeyFields: boolean;
var
  ByTable: boolean;
begin
// upd is this really nec. here
  ByTable := False;
  if UpdatingTableInfoIdx >= 0 then
{    if Self is TCustomMyTable then
      ByTable := True
    else}
      if not IsFullRefresh then
        ByTable := True;

  Result := not ByTable;
end;

procedure TCustomMyDataSetService.FillFieldDescs(out FieldDescs: TFieldDescArray;
  FillKeyFieldDescs, ForceUseAllFields: boolean);

  procedure ProcessField(FieldDesc: TMySQLFieldDesc);
  begin
    if FillKeyFieldDescs then begin
      if FieldDesc.IsKey then begin
        SetLength(FieldDescs, Length(FieldDescs) + 1);
        FieldDescs[High(FieldDescs)] := FieldDesc;
      end;
    end
    else begin
      if not FieldDesc.ReadOnly then begin
        SetLength(FieldDescs, Length(FieldDescs) + 1);
        FieldDescs[High(FieldDescs)] := FieldDesc;
      end;
    end;
  end;

  procedure CheckPrimaryKeys;
  var
    HasPrimaryKeys: boolean;
    i, j: integer;
  begin
    HasPrimaryKeys := False;
    for i := Length(FieldDescs) - 1 downto 0 do begin
      HasPrimaryKeys := (FieldDescs[i] as TMySQLFieldDesc).IsPrimaryKey;
      if HasPrimaryKeys then
        Break;
    end;

    if HasPrimaryKeys then begin
      j := 0;
      for i := 0 to Length(FieldDescs) - 1 do begin
        if (FieldDescs[i] as TMySQLFieldDesc).IsPrimaryKey then begin
          if i <> j then
            FieldDescs[j] := FieldDescs[i];
          Inc(j);
        end;
      end;
      if Length(FieldDescs) <> j then
        SetLength(FieldDescs, j);
    end;
  end;

var
  Field: TField;
  FieldDesc: TMySQLFieldDesc;
  i: integer;
  IsNeedProcessField: boolean;
begin
  FieldDescs := nil;

  if (FDataSet.Fields.Count = 0) or (GetIRecordSet.Fields.Count = 0) then
    Exit;

  for i := 0 to FDataSet.Fields.Count - 1 do begin
    Field := FDataSet.Fields[i];
    if Field.FieldKind = fkData then begin
      FieldDesc := FDataSet.GetFieldDesc(Field) as TMySQLFieldDesc;

      IsNeedProcessField := ForceUseAllFields or //(Self is TCustomMyTable) or
        (FieldDesc.TableInfo = UpdatingTableInfo) or
        ((FieldDesc.TableInfo = nil) and not FDataSet.Options.SetFieldsReadOnly);

      if IsNeedProcessField then
        ProcessField(FieldDesc);
    end;
  end;

  if FillKeyFieldDescs then
    CheckPrimaryKeys;
end;

procedure TCustomMyDataSetService.FillKeyFieldDescs(out KeyFieldDescs: TFieldDescArray; ForceUseAllKeyFields: boolean);
begin
  if (GetKeyFields <> '') or (IdentityField <> nil) then
    inherited FillKeyFieldDescs(KeyFieldDescs, ForceUseAllKeyFields)
  else
    FillFieldDescs(KeyFieldDescs, True, ForceUseAllKeyFields);
end;

procedure TCustomMyDataSetService.FillDataFieldDescs(out DataFieldDescs: TFieldDescArray; ForceUseAllKeyFields: boolean);
begin
  FillFieldDescs(DataFieldDescs, False, ForceUseAllKeyFields);
end;

function TCustomMyDataSetService.DetectIdentityField: TField;
var
  Field: TField;
  FieldDesc: TMySQLFieldDesc;
  i: integer;
begin
  Result := nil;

  /// downto to correct set FIdentityField
  for i := 0 to FDataSet.Fields.Count - 1 do begin
    Field := FDataSet.Fields[i];

    if Field.FieldKind = fkData then begin
      FieldDesc := TMySQLFieldDesc(FDataSet.GetFieldDesc(Field));

      if FieldDesc.IsAutoIncrement then begin
        Assert((FUpdatingTableInfoIdx >= - 1) and (FUpdatingTableInfoIdx < GetTablesInfo.Count));
        if (FUpdatingTableInfoIdx >= 0) and (FieldDesc.TableInfo <> nil)
          and (FieldDesc.TableInfo.TableName = GetTablesInfo[FUpdatingTableInfoIdx].TableName) then begin
          Result := Field;
          Exit;
        end;
      end;
    end;
  end;
end;

procedure TCustomMyDataSetService.CloseCursor;
begin
  inherited;
  FTimestampField := nil;
end;

procedure TCustomMyDataSetService.InitCursor;
var
  Field: TField;
  FieldDesc: TMySQLFieldDesc;
  i: integer;
begin
  inherited;

  FTimestampField := nil;

  /// downto to correct set FIdentityField
  for i := FDataSet.Fields.Count - 1 downto 0 do begin
    Field := FDataSet.Fields[i];

    if Field.FieldKind = fkData then begin
      FieldDesc := TMySQLFieldDesc(FDataSet.GetFieldDesc(Field));

      if FieldDesc.IsAutoIncrement then begin
        if FDataSet.Options.SetFieldsReadOnly then
          Field.ReadOnly := True;

        Field.AutoGenerateValue := arAutoInc;
      end;

      if (TMySQLFieldDesc(FieldDesc).MySQLType = FIELD_TYPE_TIMESTAMP) then
        FTimestampField := TMySQLFieldDesc(FieldDesc);
    end;
  end;
end;

procedure TCustomMyDataSetService.FillFieldsOrigin;
var
  Field: TField;
  FieldDesc: TMySQLFieldDesc;
  TableName: string;
  i: integer;
begin
  for i := FDataSet.Fields.Count - 1 downto 0 do begin
    Field := FDataSet.Fields[i];

    if Field.FieldKind = fkData then begin
      FieldDesc := TMySQLFieldDesc(FDataSet.GetFieldDesc(Field));

      TableName := GenerateTableName(FieldDesc);
      Field.Origin := TableName + '.' + QuoteName(FieldDesc.ActualName);
    end;
  end;
end;

procedure TCustomMyDataSetService.FillFieldsDefaultValues;

  // Must be sync with MyClasses DateTimeFromStr!!!
  function DateTimeFromStr(const Def: string; FieldDesc: TMySQLFieldDesc; var Res: TDateTime): boolean;
  //var
    //Len: integer;

    function IntAt(const Off, Len: integer): integer; // return decoded integer from string
    var
      i: integer;
    begin
      Result := 0;
      for i := 1 + Off to Off + Len do
        Result := Result * 10 + (Byte(Def[i]) - $30 {Ord('0')});
    end;

    function Year2: integer;
    begin
      Result := IntAt(0, 2);
      if Result >= 70 then
        Result := 1900 + Result
      else
        Result := 2000 + Result;
    end;

  const
    HoursPerDay = 24;

  var
    i: integer;
    t: TDateTime;
    //s: string;
  begin
    Result := True;
    //Len := Length(Def);

    case TMySQLFieldDesc(FieldDesc).MySQLType of
      FIELD_TYPE_TIMESTAMP:
        case FieldDesc.Length of
          19: // YYYY-MM-DD HH:MM:SS
            Result := TryEncodeDateTime(IntAt(0, 4), IntAt(5, 2), IntAt(8, 2), IntAt(11, 2), IntAt(14, 2), IntAt(17, 2), 0, Res);
          14: // YYYYMMDDHHMMSS
            Result := TryEncodeDateTime(IntAt(0, 4), IntAt(4, 2), IntAt(6, 2), IntAt(8, 2), IntAt(10, 2), IntAt(12, 2), 0, Res);
          12: // YYMMDDHHMMSS
            Result := TryEncodeDateTime(Year2, IntAt(2, 2), IntAt(4, 2), IntAt(6, 2), IntAt(8, 2), IntAt(10, 2), 0, Res);
          10: // YYMMDDHHMM
            Result := TryEncodeDateTime(Year2, IntAt(2, 2), IntAt(4, 2), IntAt(6, 2), IntAt(8, 2), 0, 0, Res);
          8:  // YYYYMMDD
            Result := TryEncodeDate(IntAt(0, 4), IntAt(4, 2), IntAt(6, 2), Res);
          6:  // YYMMDD
            Result := TryEncodeDate(Year2, IntAt(2, 2), IntAt(4, 2), Res);
          4:  // YYMM
            Result := TryEncodeDate(Year2, IntAt(2, 2), 1, Res);
          2:  // YY
            Result := TryEncodeDate(Year2, 1, 1, Res);
          else
            Assert(False, 'Invalid FIELD_TYPE_TIMESTAMP FieldDesc.Length (' + IntToStr(FieldDesc.Length) + ')');
        end;
      FIELD_TYPE_DATE: // YYYY-MM-DD
        Result := TryEncodeDate(IntAt(0, 4), IntAt(5, 2), IntAt(8, 2), Res);
      FIELD_TYPE_TIME: // HH:MM:SS
      begin
        i := 0;
        while Byte(Def[i + 1]) <> Byte(':') do begin
          if i >= 4 then
             DatabaseErrorFmt('Wrong time format. FieldDesc %s, value %s', [FieldDesc.Name, Def]);
          Inc(i);
        end;
        Res := (IntAt(i + 1, 2) * 60 + IntAt(i + 4, 2)) / SecsPerDay; // MM:SS

⌨️ 快捷键说明

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