zoukankan      html  css  js  c++  java
  • mormot数据集二进制序列还原

    mormot数据集二进制序列还原

    /// <summary>
    ///   数据集转二进制流单元
    /// </summary>
    unit UDBDatasetToBinary;
    
    interface
    uses
      System.SysUtils, System.Classes, Data.DB, DBAccess,SynCommons,SynTable,SynDBVCL;
    type
      /// <summary>
      ///   bit set to identify columns, e.g. null columns
      /// </summary>
      TSQLDBProxyStatementColumns = set of 0..255;
      /// <summary>
      ///   数据集转二进制流类
      /// </summary>
      TDBDatasetToBinary = class
      protected
        class procedure ColumnsToBinary(aDataSet: TDataSet;W: TFileBufferWriter;const Null: TSQLDBProxyStatementColumns;const ColTypes: TSQLDBFieldTypeDynArray);
        class function FetchAllToBinary(aDataSet: TDataSet;Dest: TStream; MaxRowCount: cardinal=0;DataRowPosition: PCardinalDynArray=nil): cardinal;
      public
        /// <summary>
        ///   数据集转二进制流
        /// </summary>
        /// <param name="aDataSet">
        ///   数据集
        /// </param>
        /// <param name="Dest">
        ///   转换后的数据流
        /// </param>
        /// <returns>
        ///   数据集记录数
        /// </returns>
        class function DataSetToBinary(aDataSet: TDataSet;Dest: TStream): cardinal;
        //TSynBinaryDataSet继承自TDataSet
        /// <summary>
        ///   二进制流转数据集
        /// </summary>
        /// <param name="Source">
        ///   数据流
        /// </param>
        /// <returns>
        ///   数据集对象
        /// </returns>
        class function BinaryToDataSet(Source: TStream):TSynBinaryDataSet;
      end;
    implementation
    
    
    { TDBDatasetToJson }
    
    { TDBDatasetToBinary }
    
    class function TDBDatasetToBinary.BinaryToDataSet(
      Source: TStream): TSynBinaryDataSet;
    begin
      Source.Position := 0;
      Result := SynDBVCL.BinaryToDataSet(nil,StreamToRawByteString(Source));
    end;
    
    class procedure TDBDatasetToBinary.ColumnsToBinary(aDataSet: TDataSet;W: TFileBufferWriter;
      const Null: TSQLDBProxyStatementColumns;
      const ColTypes: TSQLDBFieldTypeDynArray);
    var F: integer;
        VDouble: double;
        VCurrency: currency absolute VDouble;
        VDateTime: TDateTime absolute VDouble;
        colType: TSQLDBFieldType;
    begin
      for F := 0 to length(ColTypes)-1 do
      if not (F in Null) then
      begin
        colType := ColTypes[F];
        case colType of
        ftInt64:
        begin
          if aDataSet.Fields[F].DataType = TFieldType.ftBoolean then
          begin
            W.WriteVarInt64( Integer(aDataSet.Fields[F].AsBoolean) );
          end
          else
          begin
            W.WriteVarInt64( aDataSet.Fields[F].AsLargeInt);
          end;
    
        end;
        ftDouble: begin
          VDouble := aDataSet.Fields[F].AsFloat;
          W.Write(@VDouble,sizeof(VDouble));
        end;
        ftCurrency: begin
          VCurrency := aDataSet.Fields[F].AsCurrency;
          W.Write(@VCurrency,sizeof(VCurrency));
        end;
        ftDate: begin
          VDateTime := aDataSet.Fields[F].AsDateTime;
          W.Write(@VDateTime,sizeof(VDateTime));
        end;
        ftUTF8:
        begin
          if aDataSet.Fields[F].AsString = '' then
            W.Write(StringToUTF8(#0)) //如果直接传空值,解析会有问题,故改为传#0 暂时不知道这样改法有没问题 by csm 
          else
            W.Write(StringToUTF8(aDataSet.Fields[F].AsString));
          //W.Write(RawByteString(SynCommons.StringToUTF8(aDataSet.Fields[F].AsString)))
    
        end
    //    ftBlob:
    //      W.Write(ColumnBlob(F));
        else
        raise Exception.CreateFmt('ColumnsToBinary: Invalid ColumnType(%s)=%d',
          [aDataSet.Fields[F].FieldName,ord(colType)]);
      end;
    end;
    
    end;
    const
      FETCHALLTOBINARY_MAGIC = 1;
    class function TDBDatasetToBinary.DataSetToBinary(aDataSet: TDataSet;
      Dest: TStream): cardinal;
    begin
      Result := FetchAllToBinary(aDataSet,Dest);
    end;
    
    class function TDBDatasetToBinary.FetchAllToBinary(aDataSet: TDataSet;Dest: TStream;
      MaxRowCount: cardinal; DataRowPosition: PCardinalDynArray): cardinal;
    var
      F, FMax, FieldSize, NullRowSize: integer;
      StartPos: cardinal;
      Null: TSQLDBProxyStatementColumns;
      W: TFileBufferWriter;
      ColTypes: TSQLDBFieldTypeDynArray;
      function ColumnType(aFieldIdx: Integer;var aFieldSize: Integer): TSQLDBFieldType;
      begin
        //TSQLDBFieldType =(ftUnknown, ftNull, ftInt64, ftDouble, ftCurrency, ftDate, ftUTF8, ftBlob);
        case aDataSet.Fields[aFieldIdx].DataType of
          TFieldType.ftSmallint,TFieldType.ftShortint, TFieldType.ftInteger, TFieldType.ftWord, TFieldType.ftLargeint,TFieldType.ftLongWord,TFieldType.ftByte:
            Result := ftInt64;
          TFieldType.ftFloat:
            Result := ftDouble;
          TFieldType.ftCurrency:
            Result := ftCurrency;
          TFieldType.ftBoolean:
            Result := ftInt64;
          TFieldType.ftDate, TFieldType.ftTime, TFieldType.ftDateTime:
          begin
            Result := ftDate;
          end;
          TFieldType.ftString, TFieldType.ftWideString, TFieldType.ftMemo, TFieldType.ftWideMemo:
          begin
            Result := ftUTF8;
          end;
        else
          raise Exception.CreateFmt('ColumnType: invalid ColumnType(%d)=%s', [aFieldIdx, GetEnumName(Typeinfo(TFieldType), ord(aDataSet.FieldDefs[aFieldIdx].DataType))^]);
        end;
        aFieldSize := 0;
      end;
    begin
      FillChar(Null,sizeof(Null),0);
      result := 0;
      W := TFileBufferWriter.Create(Dest);
      try
        W.WriteVarUInt32(FETCHALLTOBINARY_MAGIC);
        FMax := aDataSet.FieldCount;
        W.WriteVarUInt32(FMax);
        if FMax>0 then begin
          // write column description
          SetLength(ColTypes,FMax);
          dec(FMax);
          for F := 0 to FMax do begin
            W.Write( StringToUTF8(aDataSet.Fields[F].FieldName) );
            ColTypes[F] := ColumnType(F,FieldSize);
            W.Write1(ord(ColTypes[F]));
            W.WriteVarUInt32(FieldSize);
          end;
          // initialize null handling
          NullRowSize := (FMax shr 3)+1;
          if NullRowSize>sizeof(Null) then
            raise Exception.CreateFmt('FetchAllToBinary: too many columns',[]);
          // save all data rows
          StartPos := W.TotalWritten;
          aDataSet.First;
          while not aDataSet.Eof do
          begin
            if DataRowPosition<>nil then begin
              if Length(DataRowPosition^)<=integer(result) then
                SetLength(DataRowPosition^,NextGrow(result));
              DataRowPosition^[result] := W.TotalWritten-StartPos;
            end;
            // first write null columns flags
            if NullRowSize>0 then begin
              FillChar(Null,NullRowSize,0);
              NullRowSize := 0;
            end;
            for F := 0 to FMax do
            if aDataSet.Fields[F].IsNull then begin
              include(Null,F);
              NullRowSize := (F shr 3)+1;
            end;
            W.WriteVarUInt32(NullRowSize);
            if NullRowSize>0 then
              W.Write(@Null,NullRowSize);
            // then write data values
            ColumnsToBinary(aDataSet,W,Null,ColTypes);
            inc(result);
            if (MaxRowCount>0) and (result>=MaxRowCount) then
              break;
    
            aDataSet.Next;
          end;
    
        end;
        W.Write(@result,SizeOf(result)); // fixed size at the end for row count
        W.Flush;
      finally
        W.Free;
      end;
    
    end;
    
    end.
    

      

  • 相关阅读:
    php代码覆盖率执行
    如何更好的理解(pageX,pageY,clientX,clientY,eventX,eventY,scrollX,scrollY,screenX,screenY,event.offsetX,event.offsetY,offsetLeft,style.left)
    那些曾经纠结的大小写敏感
    jQuery中的经典动画
    月末总结
    小议jQuery中的事件
    DOM操作在jQuery中的实用------文字提示和图片提示
    HTML之表单元素
    http cookie
    HTML常用字符
  • 原文地址:https://www.cnblogs.com/hnxxcxg/p/12633938.html
Copyright © 2011-2022 走看看