Advertisement
pda0

Fast TJvMemoryData loader

Mar 9th, 2018
539
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pascal 33.30 KB | None | 0 0
  1. unit DBLoader;
  2.  
  3. interface
  4. uses
  5.   SysUtils, Classes, Variants, DB, ADODB, JvMemoryDataset;
  6.  
  7. (***
  8.  * TJvMemoryDataLoader - класс для ускоренной загрузки данных из ADODataSet в
  9.  * JvMemoryData. Для использования необходимо создать экземпляр класса и вызвать
  10.  * метод FastLoad, передав в него исходный ADO набор данных, целевой MemoryData
  11.  * и строку правил для переноса полей.
  12.  * Формат строки:
  13.  *   <правило>[;<правило>][;<правило>]...
  14.  *   Правило представляет собой:
  15.  *     <целевой поле> = <поле источник>[:<модификатор>][:<модификатор>]...
  16.  *
  17.  *   Целевые поля должны быть полностью определены в структуре FieldDefs.
  18.  *   (НЕ ВСЕ ТИПЫ ПОЛЕЙ, ПОДДЕРЖИВАЕМЫЕ JvMemoryData, поддерживаются классом!)
  19.  *   Модификаторы позволяют выполнить неложные преобразования полей. Вы можете
  20.  *   указывать их в любом порядке, но выполняться они будут исключительно в том,
  21.  *   в котором определены в реализации класса.
  22.  *   Для строковых полей (включая memo) определены модификаторы:
  23.  *     trim - удаление лидирующих и завершающих пробелов
  24.  *     upper - в верхний регистр
  25.  *     lower - в нижний регистр
  26.  *   Для вещественных:
  27.  *     abs - взятие модуля
  28.  *     round - отбрасывание дробной части
  29.  *   Для целочисленных (но не для Int64):
  30.  *     abs
  31.  *   Для логических:
  32.  *     not - инверсия значения
  33.  *
  34.  * Для более сложных преобразований и формирования значений, которые нельзя
  35.  * получить из запроса существует два события: OnSetup и OnRowCopy.
  36.  * В OnSetup вы должны, при помощи метода GetFieldIndex, получить цифровые
  37.  * идентификаторы полей и в дальнейшем использовать только их при обращении к
  38.  * полям.
  39.  * Событие OnRowCopy происходит при копировании каждой строки. В событие
  40.  * передаются параметры DestHasData и Dest.
  41.  * Первый представляет собой массив Boolean, в который необходимо установить
  42.  * True для заполняемых полей. (Издержки низкоуровневой обработки).
  43.  * Второй массив ссылочных элементов, представляющих содержимое полей. Т.е. для
  44.  * полей типа ftString, ftMemo, ftFixedChar значением будет PString, для
  45.  * ftWideString, ftWideMemo - PWideString, для ftInteger - PInteger и т.д.
  46.  * Подробнее - необходимо сверятся по исходникам. (Опять же - издержки
  47.  * низкоуровневой обработки.)
  48.  * На момент этого события поля по автоматическим правилам в Dest уже заполнены
  49.  * и преобразованы модификаторами. Однако, для скорости значения неиспользуемых
  50.  * полей не очищаются и необходимо самостоятельно проверять их по значению в
  51.  * DestHasData перед использованием.
  52.  *
  53.  * После загрузки JvMemoryData устанавливается на первую запись. Не стоит делать
  54.  * предположений о состоянии ADODataSet.
  55.  *
  56.  * Общие рекомендации по ускорению загрузки:
  57.  *  1. Отбирайте в ADODataSet только необходимые поля. Чем меньше полей - тем
  58.  *     быстрее загрузка.
  59.  *  2. Если в результирующем JvMemoryData нет вычислимых или lookup-полей - не
  60.  *     ленитесь отключать свойство AutoCalcFields. (Помогает выиграть ещё до 10%
  61.  *     скорости.) Не пытайтесь схитрить и отключить это свойство перед
  62.  *     загрузкой, чтобы включить после. JvMemoryData устроен так, что подобное
  63.  *     переключение не даст эффекта - поля останутся не вычисленными.
  64.  *
  65.  * P.S. Не надо хранить строки в поле типа ftVariant. В jvMemoryData ошибка,
  66.  * приводящая к утечке памяти.
  67.  *)
  68.  
  69. {$I jvcl.inc}
  70.  
  71. type
  72.   PFieldCopyRule = ^TFieldCopyRule;
  73.   TFieldCopyRule = record
  74.     SrcField,
  75.     DstField: Integer;
  76.   end;
  77.  
  78.   TLoaderFieldModifier = (lfmStrTrim, lfmStrUpper, lfmStrLower, lfmOrdAbs,
  79.     lfmFloatRound, lfmBoolNot);
  80.   TLoaderModifiersSet = set of TLoaderFieldModifier;
  81.  
  82.   TLoaderDataMark = array of Boolean;
  83.   TLoaderCopyBuffer = array of Pointer;
  84.  
  85.   TJvMemoryDataLoader = class;
  86.   TLoaderSetupEvent = procedure(Sender: TJvMemoryDataLoader;
  87.     Src: TCustomADODataSet; Dest: TJvMemoryData) of object;
  88.   TLoaderRowCopyEvent = procedure(Sender: TJvMemoryDataLoader;
  89.     const Src: TCustomADODataSet; const Dest: TLoaderCopyBuffer;
  90.     const DestHasData: TLoaderDataMark; CurrentRow, RowCount: Integer) of object;
  91.  
  92.   TJvMemoryDataLoader = class
  93.   private
  94.     FOnSetup: TLoaderSetupEvent;
  95.     FOnRowCopy: TLoaderRowCopyEvent;
  96.     function CalcFieldLen(FieldType: TFieldType; Size: Word): Integer;
  97.     function CreateTemplate(FieldType: TFieldType): Pointer;
  98.     procedure AdjustBuffer(NewSize: Integer);
  99.   protected
  100.     FMemData: TJvMemoryData;
  101.     FAdoData: TCustomADODataSet;
  102.     FBuffer: PJvMemBuffer;
  103.     FFieldModifiers: array of TLoaderModifiersSet;
  104.     FFieldTypes: array of TFieldType;
  105.     FCopyRules: array of PFieldCopyRule;
  106.     FCopyBuffer: TLoaderCopyBuffer;
  107.     FFieldSizes,
  108.     FOffsets,
  109.     FBlobIndexes: array of Integer;
  110.     FNotNull: TLoaderDataMark;
  111.     FRow,
  112.     FRowsCount,
  113.     FBookmarkOfs,
  114.     FBlobOfs,
  115.     FRecordSize,
  116.     FRecBufSize,
  117.     FActualBufSize,
  118.     FBlobFieldCount: Integer;
  119.     {$IFDEF ADODIRECT}
  120.     FRecordSet: Variant;
  121.     {$ENDIF}
  122.     procedure SetMemData(Value: TJvMemoryData); virtual;
  123.     procedure CalcSizes; virtual;
  124.     procedure InitBuffers; virtual;
  125.     procedure CleanupBuffers; virtual;
  126.     function GetModifier(ModName: String): TLoaderFieldModifier;
  127.     procedure ParseRules(Rules: String);
  128.     procedure ValidateModifiers;
  129.     procedure CopyRuleData;
  130.     procedure CopyDataToMemoryData;
  131.   public
  132.     class function GetFieldIndex(const DataSet: TDataSet; FieldName: String):
  133.       Integer;
  134.     constructor Create; virtual;
  135.     destructor Destroy; override;
  136.     procedure Clear;
  137.     procedure FastLoad(Source: TCustomADODataSet; Destination: TJvMemoryData;
  138.       Rules: String; fClearTable: Boolean = True);
  139.     function DateTimeToInternalDate(Value: TDateTime): Longint;
  140.     function DateTimeToInternalTime(Value: TDateTime): Longint;
  141.     function DateTimeToInternalDateTime(Value: TDateTime): TDateTime;
  142.     property OnSetup: TLoaderSetupEvent read FOnSetup write FOnSetup;
  143.     property OnRowCopy: TLoaderRowCopyEvent read FOnRowCopy write FOnRowCopy;
  144.   end;
  145.  
  146. implementation
  147. uses
  148.   Math;
  149.  
  150. type
  151.   { !! Depended of TJvMemoryData implementation !! }
  152.   TCopyOfBookmarkData = Integer;
  153.   TCopyOfMemBookmarkInfo = record
  154.     BookmarkData: TCopyOfBookmarkData;
  155.     BookmarkFlag: TBookmarkFlag;
  156.   end;
  157.  
  158. const
  159.   { !! Depended of TJvMemoryData implementation !! }
  160.   BOOKMARK_INTERNAL_SIZE = SizeOf(TCopyOfMemBookmarkInfo);
  161.  
  162.   GUID_SIZE = 38;
  163.  
  164.   ftBlobTypes = [{ftBlob,} ftMemo
  165.     {$IFDEF COMPILER10_UP}, ftWideMemo{$ENDIF COMPILER10_UP}];
  166.  
  167.   ftSupported = [ftString, ftSmallint, ftInteger, ftWord, ftBoolean,
  168.     ftFloat, ftCurrency, ftDate, ftTime, ftDateTime, ftAutoInc, ftTimestamp,
  169.     {$IFDEF COMPILER10_UP}
  170.     ftFixedWideChar,
  171.     {$ENDIF COMPILER10_UP}
  172.     {$IFDEF COMPILER12_UP}
  173.     ftLongWord, ftShortint, ftByte, ftExtended,
  174.     {$ENDIF COMPILER12_UP}
  175.     ftFixedChar, ftWideString, ftLargeint, ftVariant, ftGuid] + ftBlobTypes;
  176.  
  177. type
  178.   THackMemoryData = class(TJvMemoryData)
  179.   public
  180.     procedure InternalAddRecord(Buffer: Pointer; Append: Boolean); override;
  181.     function GetActiveRecBuf(var RecBuf: PJvMemBuffer): Boolean; override;
  182.     procedure CalculateFields(Buffer: PChar); override;
  183.     property CalcFieldsSize;
  184.   end;
  185.  
  186. { TJvMemoryDataLoader }
  187.  
  188. constructor TJvMemoryDataLoader.Create;
  189. begin
  190.   FActualBufSize := 0;
  191.   FBuffer := nil;
  192.   Initialize(FCopyBuffer);
  193.   Initialize(FCopyRules);
  194.   Clear;
  195. end;
  196.  
  197. destructor TJvMemoryDataLoader.Destroy;
  198. begin
  199.   Clear;
  200.  
  201.   Finalize(FCopyRules);
  202.   Finalize(FCopyBuffer);
  203.   inherited;
  204. end;
  205.  
  206. function TJvMemoryDataLoader.CalcFieldLen(FieldType: TFieldType;
  207.   Size: Word): Integer;
  208. begin
  209.   if not (FieldType in ftSupported) then
  210.     Result := 0
  211.   else
  212.   if (FieldType in ftBlobTypes) then
  213.     begin
  214.       Result := 0;
  215.     end                       else
  216.     begin
  217.       Result := Size;
  218.       case FieldType of
  219.         ftString:
  220.           Inc(Result);
  221.         ftSmallint:
  222.           Result := SizeOf(Smallint);
  223.         ftInteger:
  224.           Result := SizeOf(Longint);
  225.         ftWord:
  226.           Result := SizeOf(Word);
  227.         ftBoolean:
  228.           Result := SizeOf(Wordbool);
  229.         ftFloat:
  230.           Result := SizeOf(Double);
  231.         ftCurrency:
  232.           Result := SizeOf(Double);
  233.         ftDate, ftTime:
  234.           Result := SizeOf(Longint);
  235.         ftDateTime:
  236.           Result := SizeOf(TDateTime);
  237.         ftAutoInc:
  238.           Result := SizeOf(Longint);
  239.         ftFixedChar:
  240.           Inc(Result);
  241.         ftWideString:
  242.           Result := (Result+1)*SizeOf(WideChar);
  243.         ftLargeint:
  244.           Result := SizeOf(Int64);
  245.         ftVariant:
  246.           Result := SizeOf(Variant);
  247.         ftGuid:
  248.           Result := GUID_SIZE+1;
  249.         else
  250.           raise Exception.Create('');
  251.       end;
  252.     end;
  253. end;
  254.  
  255. function TJvMemoryDataLoader.CreateTemplate(FieldType: TFieldType): Pointer;
  256. begin
  257.   if not (FieldType in ftSupported) then
  258.     begin
  259.     Result := nil;
  260.     end                             else
  261.     begin
  262.       case FieldType of
  263.         ftString, ftFixedChar, ftMemo, ftGuid:
  264.           begin
  265.             New(PString(Result));
  266.             Initialize(PString(Result)^);
  267.           end;
  268.         ftSmallint:
  269.           New(PSmallInt(Result));
  270.         ftInteger:
  271.           New(PInteger(Result));
  272.         ftWord:
  273.           New(PWord(Result));
  274.         ftBoolean:
  275.           New(PWordbool(Result));
  276.         ftFloat, ftCurrency:
  277.           New(PDouble(Result));
  278.         ftDate, ftTime:
  279.           New(PLongint(Result));
  280.         ftDateTime:
  281.           New(PDateTime(Result));
  282.         ftAutoInc:
  283.           New(PLongint(Result));
  284.         ftWideString, ftWideMemo:
  285.           begin
  286.             New(PWideString(Result));
  287.             Initialize(PWideString(Result)^);
  288.           end;
  289.         ftLargeint:
  290.           New(PInt64(Result));
  291.         ftVariant:
  292.           begin
  293.             New(PVariant(Result));
  294.             PVariant(Result)^ := Unassigned;
  295.           end
  296.         else
  297.           raise Exception.Create('');
  298.       end;
  299.     end;
  300. end;
  301.  
  302. procedure TJvMemoryDataLoader.CalcSizes;
  303. var
  304.   i: Integer;
  305. begin
  306.   FBlobFieldCount := 0;
  307.   SetLength(FFieldModifiers, FMemData.FieldDefs.Count);
  308.   SetLength(FFieldTypes, FMemData.FieldDefs.Count);
  309.   SetLength(FOffsets, FMemData.FieldDefs.Count);
  310.   SetLength(FFieldSizes, FMemData.FieldDefs.Count);
  311.   SetLength(FCopyBuffer, FMemData.FieldDefs.Count);
  312.   SetLength(FBlobIndexes, FMemData.FieldDefs.Count);
  313.   SetLength(FNotNull, FMemData.FieldDefs.Count);
  314.   for i := Low(FFieldModifiers) to High(FFieldModifiers) do FFieldModifiers[i] := [];
  315.   FillChar(FOffsets[0], SizeOf(Integer)*Length(FOffsets), 0);
  316.   FillChar(FFieldSizes[0], SizeOf(Integer)*Length(FFieldSizes), 0);
  317.   FillChar(FCopyBuffer[0], SizeOf(Pointer)*Length(FCopyBuffer), 0);
  318.   for i := Low(FBlobIndexes) to High(FBlobIndexes) do FBlobIndexes[i] := -1;
  319.   FRecordSize := 1;
  320.   for i:= 0 to (FMemData.FieldDefs.Count-1) do
  321.     if (FMemData.FieldDefs[i].DataType in ftSupported) then
  322.       begin
  323.         FOffsets[i] := FRecordSize;
  324.         try
  325.           FFieldTypes[i] := FMemData.FieldDefs[i].DataType;
  326.           FFieldSizes[i] := CalcFieldLen(FFieldTypes[i], FMemData.FieldDefs[i].Size);
  327.  
  328.           FCopyBuffer[i] := CreateTemplate(FFieldTypes[i]);
  329.           if (FFieldTypes[i] in ftBlobTypes) then
  330.             begin
  331.               FBlobIndexes[i] := FBlobFieldCount;
  332.               Inc(FBlobFieldCount);
  333.             end;
  334.         except
  335.           raise Exception.Create('TJvMemoryDataLoader unable to load data, unsupported field type for field: '+FMemData.FieldDefs[i].Name+'.');
  336.         end;
  337.         if (FMemData.FieldDefs[i].ChildDefs.Count > 0) then
  338.           raise Exception.Create('TJvMemoryDataLoader is not support child fields for field: '+FMemData.FieldDefs[i].Name+'.');
  339.  
  340.         if (FFieldSizes[i] > 0) then
  341.           begin
  342.             FRecordSize := FRecordSize+FFieldSizes[i]+1;
  343.           end                   else
  344.           begin
  345.             FOffsets[i] := -1;
  346.           end;
  347.       end;
  348.   Dec(FRecordSize);
  349.  
  350.   FBookmarkOfs := FRecordSize+THackMemoryData(FMemData).CalcFieldsSize;
  351.   FBlobOfs := FBookmarkOfs+BOOKMARK_INTERNAL_SIZE;
  352.   FRecBufSize := FBlobOfs+FBlobFieldCount*SizeOf(Pointer);
  353. end;
  354.  
  355. procedure TJvMemoryDataLoader.AdjustBuffer(NewSize: Integer);
  356. begin
  357.   if (NewSize > FActualBufSize) then
  358.     begin
  359.       if Assigned(FBuffer) then
  360.         ReallocMem(FBuffer, NewSize)
  361.       else
  362.         GetMem(FBuffer, NewSize);
  363.  
  364.       FActualBufSize := NewSize;
  365.     end;
  366. end;
  367.  
  368. procedure TJvMemoryDataLoader.InitBuffers;
  369. begin
  370.   AdjustBuffer(FRecBufSize);
  371.   FillChar(FBuffer^, FActualBufSize, 0);
  372.   if (FBlobFieldCount > 0) then
  373.     Initialize(PMemBlobArray(NativeInt(FBuffer)+FBlobOfs)^[0], FBlobFieldCount);
  374. end;
  375.  
  376. procedure TJvMemoryDataLoader.CleanupBuffers;
  377. var
  378.   i: Integer;
  379. begin
  380.   FillChar(FBuffer^, FBlobOfs, 0);
  381.  
  382.   for i := 0 to (FBlobFieldCount-1) do
  383.     begin
  384.       PMemBlobArray(NativeInt(FBuffer)+FBlobOfs)^[i] := '';
  385.     end;
  386.   FillChar(FNotNull[0], Length(FNotNull)*SizeOf(Boolean), 0);
  387. end;
  388.  
  389. class function TJvMemoryDataLoader.GetFieldIndex(const DataSet: TDataSet;
  390.   FieldName: String): Integer;
  391. begin
  392.   Result := DataSet.FieldByName(FieldName).Index;
  393. end;
  394.  
  395. function TJvMemoryDataLoader.GetModifier(ModName: String): TLoaderFieldModifier;
  396. begin
  397.   ModName := AnsiLowerCase(ModName);
  398.   if (ModName = 'trim') then
  399.     begin
  400.       Result := lfmStrTrim;
  401.     end
  402.   else if (ModName = 'upper') then
  403.     begin
  404.       Result := lfmStrUpper;
  405.     end
  406.   else if (ModName = 'lower') then
  407.     begin
  408.       Result := lfmStrLower;
  409.     end
  410.   else if (ModName = 'abs') then
  411.     begin
  412.       Result := lfmOrdAbs;
  413.     end
  414.   else if (ModName = 'round') then
  415.     begin
  416.       Result := lfmFloatRound;
  417.     end
  418.   else if (ModName = 'not') then
  419.     begin
  420.       Result := lfmBoolNot;
  421.     end
  422.   else
  423.     begin
  424.       raise Exception.Create('FastLoad: Unknown field modifier type: '+ModName);
  425.     end;
  426. end;
  427.  
  428. procedure TJvMemoryDataLoader.ParseRules(Rules: String);
  429. var
  430.   Modifiers: TLoaderModifiersSet;
  431.   NewCopyRule: PFieldCopyRule;
  432.   Rule, SrcFieldMods, SrcFieldName, DstFieldName: String;
  433.   cIdx, eIdx, mIdx: Integer;
  434. begin
  435.   if (Rules = '') then
  436.     Exit;
  437.  
  438.   repeat
  439.     cIdx := Pos(';', Rules);
  440.     if (cIdx > 0) then
  441.       begin
  442.         Rule := Copy(Rules, 1, cIdx-1);
  443.         Delete(Rules, 1, cIdx);
  444.       end         else
  445.       begin
  446.         Rule := Rules;
  447.       end;
  448.  
  449.     eIdx := Pos('=', Rule);
  450.     if (eIdx > 0) then
  451.       begin
  452.         Modifiers := [];
  453.         SrcFieldName := '';
  454.         DstFieldName := Trim(Copy(Rule, 1, eIdx-1));
  455.         SrcFieldMods := Trim(Copy(Rule, eIdx+1, Length(Rule)-eIdx));
  456.         repeat
  457.           mIdx := Pos(':', SrcFieldMods);
  458.  
  459.           if (SrcFieldName = '') then
  460.             begin
  461.               SrcFieldName := Trim(Copy(SrcFieldMods, 1, mIdx-1));
  462.             end                  else
  463.             begin
  464.               if (mIdx > 0) then
  465.                 Modifiers := Modifiers+[GetModifier(Trim(Copy(SrcFieldMods, 1, mIdx-1)))]
  466.               else
  467.                 Modifiers := Modifiers+[GetModifier(Trim(SrcFieldMods))];
  468.             end;
  469.           SrcFieldMods := Trim(Copy(SrcFieldMods, mIdx+1, Length(SrcFieldMods)-mIdx));
  470.         until (mIdx = 0);
  471.  
  472.         if (SrcFieldName = '') then
  473.           SrcFieldName := SrcFieldMods;
  474.  
  475.         New(NewCopyRule);
  476.         NewCopyRule^.SrcField := GetFieldIndex(FAdoData, SrcFieldName);
  477.         NewCopyRule^.DstField := GetFieldIndex(FMemData, DstFieldName);
  478.         FFieldModifiers[NewCopyRule^.DstField] := Modifiers;
  479.         SetLength(FCopyRules, Length(FCopyRules)+1);
  480.         FCopyRules[High(FCopyRules)] := NewCopyRule;
  481.       end         else
  482.       begin
  483.         raise Exception.Create('FastLoad: Invalid rules format.');
  484.       end;
  485.   until (cIdx = 0);
  486. end;
  487.  
  488. procedure TJvMemoryDataLoader.SetMemData(Value: TJvMemoryData);
  489. begin
  490.   if (Value.FieldDefs.Count = 0) then
  491.     raise Exception.Create('TJvMemoryDataLoader required predefined fields for loading.');
  492.  
  493.   FMemData := Value;
  494.   CalcSizes;
  495.   InitBuffers;
  496. end;
  497.  
  498. procedure TJvMemoryDataLoader.Clear;
  499. var
  500.   i: Integer;
  501. begin
  502.   if Assigned(FBuffer) then
  503.     begin
  504.       if (FBlobFieldCount > 0) then
  505.         Finalize(PMemBlobArray(NativeInt(FBuffer)+FBlobOfs)^[0], FBlobFieldCount);
  506.  
  507.       FreeMem(FBuffer);
  508.       FBuffer := nil;
  509.       FActualBufSize := 0;
  510.     end;
  511.  
  512.   if (Length(FCopyBuffer) > 0) then
  513.     begin
  514.       for i := Low(FCopyBuffer) to High(FCopyBuffer) do
  515.         if Assigned(FCopyBuffer[i]) then
  516.           begin
  517.             case FFieldTypes[i] of
  518.               ftString, ftFixedChar, ftMemo:
  519.                 begin
  520.                   Finalize(PString(FCopyBuffer[i])^);
  521.                 end;
  522.               ftWideString, ftWideMemo:
  523.                 begin
  524.                   Finalize(PWideString(FCopyBuffer[i])^);
  525.                 end;
  526.               ftVariant:
  527.                 begin
  528.                   PVariant(FCopyBuffer[i])^ := Unassigned;
  529.                 end;
  530.             end;
  531.             Dispose(FCopyBuffer[i]);
  532.           end;
  533.  
  534.       SetLength(FCopyBuffer, 0);
  535.     end;
  536.  
  537.   if (Length(FCopyRules) > 0) then
  538.     begin
  539.       for i := Low(FCopyRules) to High(FCopyRules) do
  540.         if Assigned(FCopyRules[i]) then
  541.           Dispose(FCopyRules[i]);
  542.  
  543.       SetLength(FCopyRules, 0);
  544.     end;
  545.  
  546.   SetLength(FFieldTypes, 0);
  547. end;
  548.  
  549. procedure TJvMemoryDataLoader.ValidateModifiers;
  550. var
  551.   i: Integer;
  552.  
  553.   procedure InvalidModifier(DstField: Integer);
  554.   begin
  555.     raise Exception.Create('FastLoad: Unsupported modifier type for field: '+
  556.       FMemData.Fields[DstField].FieldName);
  557.   end;
  558. begin
  559.   for i := Low(FFieldModifiers) to High(FFieldModifiers) do
  560.     case FFieldTypes[i] of
  561.       ftSmallint, ftInteger, ftWord, ftAutoInc, ftLargeint:
  562.         if ((FFieldModifiers[i]-[lfmOrdAbs]) <> []) then
  563.           begin
  564.             InvalidModifier(i);
  565.           end;
  566.       ftFloat, ftCurrency:
  567.         if ((FFieldModifiers[i]-[lfmOrdAbs, lfmFloatRound]) <> []) then
  568.           begin
  569.             InvalidModifier(i);
  570.           end;
  571.       ftFixedChar, ftString, ftMemo, ftWideString, ftWideMemo:
  572.         if ((FFieldModifiers[i]-[lfmStrTrim, lfmStrLower, lfmStrLower]) <> []) then
  573.           begin
  574.             InvalidModifier(i);
  575.           end;
  576.       ftBoolean:
  577.         if ((FFieldModifiers[i]-[lfmBoolNot]) <> []) then
  578.           begin
  579.             InvalidModifier(i);
  580.           end;
  581.       ftDate, ftTime, ftDateTime, ftVariant, ftGuid:
  582.         if (FFieldModifiers[i] <> []) then
  583.           begin
  584.             InvalidModifier(i);
  585.           end;
  586.       else
  587.         begin
  588.           raise Exception.Create('FastLoad: FIXME: Need to add type of field '+
  589.             FMemData.Fields[i].FieldName+' for modifier checking.');
  590.         end;
  591.     end;
  592. end;
  593.  
  594. procedure TJvMemoryDataLoader.CopyRuleData;
  595. var
  596.   i, SrcField, DstField: Integer;
  597.   {$IFDEF ADODIRECT}
  598.   Guid: String;
  599.   {$ENDIF}
  600.  
  601.   function HandleStrMod(AStr: String; DstField: Integer): String;
  602.   begin
  603.     Result := AStr;
  604.  
  605.     if (lfmStrTrim in FFieldModifiers[DstField]) then
  606.       Result := Trim(Result);
  607.  
  608.     if (lfmStrUpper in FFieldModifiers[DstField]) then
  609.       Result := AnsiUpperCase(Result);
  610.  
  611.     if (lfmStrLower in FFieldModifiers[DstField]) then
  612.       Result := AnsiLowerCase(Result);
  613.   end;
  614.   function HandleWideStrMod(AWideStr: WideString; DstField: Integer): WideString;
  615.   begin
  616.     Result := AWideStr;
  617.  
  618.     if (lfmStrTrim in FFieldModifiers[DstField]) then
  619.       Result := Trim(Result);
  620.  
  621.     if (lfmStrUpper in FFieldModifiers[DstField]) then
  622.       Result := WideUpperCase(Result);
  623.  
  624.     if (lfmStrLower in FFieldModifiers[DstField]) then
  625.       Result := WideLowerCase(Result);
  626.   end;
  627.   function HandleIntMod(AInt: Integer; DstField: Integer): Integer;
  628.   begin
  629.     Result := AInt;
  630.  
  631.     if (lfmOrdAbs in FFieldModifiers[DstField]) then
  632.       Result := Abs(Result);
  633.   end;
  634.   function HandleInt64Mod(AInt: Int64; DstField: Integer): Int64;
  635.   begin
  636.     Result := AInt;
  637.  
  638.     if (lfmOrdAbs in FFieldModifiers[DstField]) then
  639.       Result := Abs(Result);
  640.   end;
  641.   function HandleFloatMod(AFloat: Double; DstField: Integer): Double;
  642.   begin
  643.     Result := AFloat;
  644.  
  645.     if (lfmOrdAbs in FFieldModifiers[DstField]) then
  646.       Result := Abs(Result);
  647.  
  648.     if (lfmFloatRound in FFieldModifiers[DstField]) then
  649.       Result := Round(Result);
  650.   end;
  651.   function HandleBoolMod(ABool: WordBool; DstField: Integer): WordBool;
  652.   begin
  653.     Result := ABool;
  654.  
  655.     if (lfmBoolNot in FFieldModifiers[DstField]) then
  656.       Result := not(Result);
  657.   end;
  658. begin
  659.   for i := Low(FCopyRules) to High(FCopyRules) do
  660.     begin
  661.       SrcField := PFieldCopyRule(FCopyRules[i])^.SrcField;
  662.       DstField := PFieldCopyRule(FCopyRules[i])^.DstField;
  663.  
  664.       {$IFDEF ADODIRECT}
  665.       FNotNull[DstField] := not(VarIsNull(FRecordSet.Fields[SrcField].Value));
  666.       {$ELSE}
  667.       FNotNull[DstField] := not(FAdoData.Fields[SrcField].IsNull);
  668.       {$ENDIF}
  669.  
  670.       if FNotNull[DstField] then
  671.         case FFieldTypes[DstField] of
  672.           ftString, ftFixedChar, ftMemo:
  673.             {$IFDEF ADODIRECT}
  674.             PString(FCopyBuffer[DstField])^ := HandleStrMod(FRecordSet.Fields[SrcField].Value, DstField);
  675.             {$ELSE}
  676.             PString(FCopyBuffer[DstField])^ := HandleStrMod(FAdoData.Fields[SrcField].AsString, DstField);
  677.             {$ENDIF}
  678.           ftWideString, ftWideMemo:
  679.             {$IFDEF ADODIRECT}
  680.             PWideString(FCopyBuffer[DstField])^ := HandleWideStrMod(FRecordSet.Fields[SrcField].Value, DstField);
  681.             {$ELSE}
  682.             PWideString(FCopyBuffer[DstField])^ := HandleWideStrMod(FAdoData.Fields[SrcField].AsWideString, DstField);
  683.             {$ENDIF}
  684.           ftSmallint:
  685.             {$IFDEF ADODIRECT}
  686.             PSmallInt(FCopyBuffer[DstField])^ := HandleIntMod(FRecordSet.Fields[SrcField].Value, DstField);
  687.             {$ELSE}
  688.             PSmallInt(FCopyBuffer[DstField])^ := HandleIntMod(FAdoData.Fields[SrcField].AsInteger, DstField);
  689.             {$ENDIF}
  690.           ftInteger:
  691.             {$IFDEF ADODIRECT}
  692.             PInteger(FCopyBuffer[DstField])^ := HandleIntMod(FRecordSet.Fields[SrcField].Value, DstField);
  693.             {$ELSE}
  694.             PInteger(FCopyBuffer[DstField])^ := HandleIntMod(FAdoData.Fields[SrcField].AsInteger, DstField);
  695.             {$ENDIF}
  696.           ftWord:
  697.             {$IFDEF ADODIRECT}
  698.             PWord(FCopyBuffer[DstField])^ := HandleIntMod(FRecordSet.Fields[SrcField].Value, DstField);
  699.             {$ELSE}
  700.             PWord(FCopyBuffer[DstField])^ := HandleIntMod(FAdoData.Fields[SrcField].AsInteger, DstField);
  701.             {$ENDIF}
  702.           ftBoolean:
  703.             {$IFDEF ADODIRECT}
  704.             PWordbool(FCopyBuffer[DstField])^ := HandleBoolMod(FRecordSet.Fields[SrcField].Value, DstField);
  705.             {$ELSE}
  706.             if (FAdoData.Fields[SrcField].DataType = ftBoolean) then
  707.               PWordbool(FCopyBuffer[DstField])^ := HandleBoolMod(FAdoData.Fields[SrcField].AsBoolean, DstField)
  708.             else
  709.               PWordbool(FCopyBuffer[DstField])^ := HandleBoolMod((FAdoData.Fields[SrcField].AsInteger <> 0), DstField);
  710.             {$ENDIF}
  711.           ftFloat, ftCurrency:
  712.             {$IFDEF ADODIRECT}
  713.             PDouble(FCopyBuffer[DstField])^ := HandleFloatMod(FRecordSet.Fields[SrcField].Value, DstField);
  714.             {$ELSE}
  715.             PDouble(FCopyBuffer[DstField])^ := HandleFloatMod(FAdoData.Fields[SrcField].AsFloat, DstField);
  716.             {$ENDIF}
  717.           ftDate:
  718.             {$IFDEF ADODIRECT}
  719.             PLongint(FCopyBuffer[DstField])^ := DateTimeToInternalDate(FRecordSet.Fields[SrcField].Value);
  720.             {$ELSE}
  721.             PLongint(FCopyBuffer[DstField])^ := DateTimeToInternalDate(FAdoData.Fields[SrcField].AsDateTime);
  722.             {$ENDIF}
  723.           ftTime:
  724.             {$IFDEF ADODIRECT}
  725.             PLongint(FCopyBuffer[DstField])^ := DateTimeToInternalTime(FRecordSet.Fields[SrcField].Value);
  726.             {$ELSE}
  727.             PLongint(FCopyBuffer[DstField])^ := DateTimeToInternalTime(FAdoData.Fields[SrcField].AsDateTime);
  728.             {$ENDIF}
  729.           ftDateTime:
  730.             {$IFDEF ADODIRECT}
  731.             PDateTime(FCopyBuffer[DstField])^ := DateTimeToInternalDateTime(FRecordSet.Fields[SrcField].Value);
  732.             {$ELSE}
  733.             PDateTime(FCopyBuffer[DstField])^ := DateTimeToInternalDateTime(FAdoData.Fields[SrcField].AsDateTime);
  734.             {$ENDIF}
  735.           ftAutoInc:
  736.             {$IFDEF ADODIRECT}
  737.             PLongint(FCopyBuffer[DstField])^ := HandleIntMod(FRecordSet.Fields[SrcField].Value, DstField);
  738.             {$ELSE}
  739.             PLongint(FCopyBuffer[DstField])^ := HandleIntMod(FAdoData.Fields[SrcField].AsInteger, DstField);
  740.             {$ENDIF}
  741.           ftLargeint:
  742.             try
  743.               {$IFDEF ADODIRECT}
  744.               PInt64(FCopyBuffer[DstField])^ := HandleInt64Mod(VarAsType(FRecordSet.Fields[SrcField].Value, varInt64), DstField);
  745.               {$ELSE}
  746.               PInt64(FCopyBuffer[DstField])^ := HandleInt64Mod(VarAsType((FAdoData.Fields[SrcField] as TLargeintField).Value, varInt64), DstField);
  747.               {$ENDIF}
  748.             except
  749.               PInt64(FCopyBuffer[DstField])^ := 0;
  750.             end;
  751.           ftGuid: //not tested
  752.             begin
  753.               SetLength(PString(FCopyBuffer[DstField])^, GUID_SIZE);
  754.               FillChar(PString(FCopyBuffer[DstField])^, GUID_SIZE, #0);
  755.               {$IFDEF ADODIRECT}
  756.               Guid := VarToStr(FRecordSet.Fields[SrcField].Value);
  757.               Move(Guid[1], PString(FCopyBuffer[DstField])^[1],  Max(Length(Guid), GUID_SIZE));
  758.               {$ELSE}
  759.               Move(FAdoData.Fields[SrcField].AsString[1], PString(FCopyBuffer[DstField])^[1],
  760.                  Max(Length(FAdoData.Fields[SrcField].AsString), GUID_SIZE));
  761.               {$ENDIF}
  762.             end;
  763.           ftVariant:
  764.             {$IFDEF ADODIRECT}
  765.             PVariant(FCopyBuffer[DstField])^ := FRecordSet.Fields[SrcField].Value;
  766.             {$ELSE}
  767.             PVariant(FCopyBuffer[DstField])^ := FAdoData.Fields[SrcField].Value;
  768.             {$ENDIF}
  769.         end;
  770.     end;
  771. end;
  772.  
  773. procedure TJvMemoryDataLoader.CopyDataToMemoryData;
  774. var
  775.   i: Integer;
  776. begin
  777.   for i := 0 to High(FCopyBuffer) do
  778.     if FNotNull[i] then
  779.       begin
  780.         if not(FFieldTypes[i] in ftBlobTypes) then
  781.           PByte(NativeInt(FBuffer)+FOffsets[i]-1)^ := 1; { not NULL }
  782.  
  783.         case FFieldTypes[i] of
  784.           ftSmallint, ftInteger, ftWord, ftBoolean, ftFloat, ftCurrency, ftDate,
  785.           ftTime, ftDateTime, ftAutoInc, ftLargeint:
  786.             begin
  787.               Move(FCopyBuffer[i]^, Pointer(NativeInt(FBuffer)+FOffsets[i])^, FFieldSizes[i]);
  788.             end;
  789.           ftFixedChar, ftString:
  790.             begin
  791.              FillChar(Pointer(NativeInt(FBuffer)+FOffsets[i])^, FFieldSizes[i], 0);
  792.                Move(PString(FCopyBuffer[i])^[1], Pointer(NativeInt(FBuffer)+FOffsets[i])^,
  793.                Min(Length(PString(FCopyBuffer[i])^)*SizeOf(Char), FFieldSizes[i]-SizeOf(Char)));
  794.             end;
  795.           ftWideString:
  796.             begin
  797.               FillChar(Pointer(NativeInt(FBuffer)+FOffsets[i])^, FFieldSizes[i], 0);
  798.               Move(PWideString(FCopyBuffer[i])^[1], Pointer(NativeInt(FBuffer)+FOffsets[i])^,
  799.                 Min(Length(PWideString(FCopyBuffer[i])^)*SizeOf(WideChar), FFieldSizes[i]-SizeOf(WideChar)));
  800.             end;
  801.           ftMemo:
  802.             begin
  803.               PMemBlobArray(NativeInt(FBuffer)+FBlobOfs)^[FBlobIndexes[i]] := PString(FCopyBuffer[i])^;
  804.             end;
  805.           ftWideMemo:
  806.             begin
  807.               if (Length(PWideString(FCopyBuffer[i])^) > 0) then
  808.                 begin
  809.                   SetLength(PMemBlobArray(NativeInt(FBuffer)+FBlobOfs)[FBlobIndexes[i]],
  810.                      Length(PWideString(FCopyBuffer[i])^)*SizeOf(WideChar));
  811.                   Move(PWideString(FCopyBuffer[i])^[1],
  812.                     PMemBlobArray(NativeInt(FBuffer)+FBlobOfs)^[FBlobIndexes[i]][1],
  813.                     Length(PWideString(FCopyBuffer[i])^)*SizeOf(WideChar));
  814.                 end;
  815.             end;
  816.           ftVariant:
  817.             begin
  818.               PVariant(NativeInt(FBuffer)+FOffsets[i])^ := PVariant(FCopyBuffer[i])^;
  819.             end;
  820.           ftGuid: //not tested
  821.             begin
  822.               Move(PString(FCopyBuffer[i])^[1], Pointer(NativeInt(FBuffer)+FOffsets[i])^, GUID_SIZE);
  823.             end;
  824.           else
  825.             begin
  826.               raise Exception.Create('FastLoad: Unsupported field type (copy).');
  827.             end;
  828.         end;
  829.       end          else
  830.       begin
  831.         case FFieldTypes[i] of
  832.           ftVariant:
  833.             begin
  834.               PVariant(NativeInt(FBuffer)+FOffsets[i])^ := EmptyParam;
  835.             end;
  836.         end;
  837.       end;
  838.    
  839.   THackMemoryData(FMemData).InternalAddRecord(FBuffer, True);
  840. end;
  841.  
  842. procedure TJvMemoryDataLoader.FastLoad(Source: TCustomADODataSet; Destination:
  843.   TJvMemoryData; Rules: String; fClearTable: Boolean = True);
  844. var
  845.   CalcBuffer: PJvMemBuffer;
  846. begin
  847.   Clear;
  848.   SetMemData(Destination);
  849.   FAdoData := Source;
  850.  
  851.   FMemData.DisableControls;
  852.   FAdoData.DisableControls;
  853.   try
  854.     if fClearTable then
  855.     begin
  856.       FMemData.Close;
  857.       FMemData.EmptyTable;
  858.       FMemData.Open;
  859.     end;
  860.     ParseRules(Rules); { Parse it here, because field need to be created first. }
  861.     ValidateModifiers;
  862.  
  863.     if Assigned(FOnSetup) then
  864.       FOnSetup(Self, FAdoData, FMemData);
  865.  
  866.     {$IFDEF ADODIRECT}
  867.     FRecordSet := FAdoData.Recordset;
  868.     if not(FRecordSet.BOF and FRecordSet.EOF) then
  869.       FRecordSet.MoveFirst;
  870.     {$ELSE}
  871.     FAdoData.First;
  872.     {$ENDIF}
  873.  
  874.     FRow := 0;
  875.     FRowsCount := {$IFDEF ADODIRECT}FRecordSet{$ELSE}FAdoData{$ENDIF}.RecordCount;
  876.     while not({$IFDEF ADODIRECT}FRecordSet.EOF{$ELSE}FAdoData.Eof{$ENDIF}) do
  877.       begin
  878.         CleanupBuffers;
  879.         CopyRuleData;
  880.  
  881.         if Assigned(FOnRowCopy) then
  882.           FOnRowCopy(Self, FAdoData, FCopyBuffer, FNotNull, FRow, FRowsCount);
  883.  
  884.         CopyDataToMemoryData;
  885.  
  886.         {$IFNDEF ADODIRECT}
  887.         FAdoData.Next;
  888.         {$ELSE}
  889.         FAdoData.Recordset.MoveNext;
  890.         {$ENDIF}
  891.         Inc(FRow);
  892.       end;
  893.  
  894.     FMemData.Resync([]);
  895.     FMemData.First;
  896.  
  897.     FAdoData.Resync([]);
  898.     FAdoData.First;
  899.  
  900.     if FMemData.AutoCalcFields then
  901.       begin
  902.         while not(FMemData.Eof) do
  903.           begin
  904.             FMemData.Edit;
  905.             THackMemoryData(FMemData).GetActiveRecBuf(CalcBuffer);
  906.             THackMemoryData(FMemData).CalculateFields(CalcBuffer);
  907.             FMemData.Post;
  908.             FMemData.Next;
  909.           end;
  910.         FMemData.First;
  911.       end;
  912.   finally
  913.     FAdoData.EnableControls;
  914.     FMemData.EnableControls;
  915.   end;
  916. end;
  917.  
  918. function TJvMemoryDataLoader.DateTimeToInternalDate(Value: TDateTime): Longint;
  919. var
  920.   TimeStamp: TTimeStamp;
  921. begin
  922.   TimeStamp := DateTimeToTimeStamp(Value);
  923.   Result := TimeStamp.Date;
  924. end;
  925.  
  926. function TJvMemoryDataLoader.DateTimeToInternalTime(Value: TDateTime): Longint;
  927. var
  928.   TimeStamp: TTimeStamp;
  929. begin
  930.   TimeStamp := DateTimeToTimeStamp(Value);
  931.   Result := TimeStamp.Time;
  932. end;
  933.  
  934. function TJvMemoryDataLoader.DateTimeToInternalDateTime(Value: TDateTime): TDateTime;
  935. var
  936.   TimeStamp: TTimeStamp;
  937. begin
  938.   TimeStamp := DateTimeToTimeStamp(Value);
  939.   Result := TimeStampToMSecs(TimeStamp);
  940. end;
  941.  
  942. { THackMemoryData }
  943.  
  944. procedure THackMemoryData.CalculateFields(Buffer: PChar);
  945. begin
  946.   inherited;
  947. end;
  948.  
  949. procedure THackMemoryData.InternalAddRecord(Buffer: Pointer; Append: Boolean);
  950. begin
  951.   inherited;
  952. end;
  953.  
  954. function THackMemoryData.GetActiveRecBuf(var RecBuf: PJvMemBuffer): Boolean;
  955. begin
  956.   Result := inherited GetActiveRecBuf(RecBuf);
  957. end;
  958.  
  959. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement