make on the current record, depends on the
setting of
setting of
EnableVersioningEnableVersioningand and
VersioningMode.
VersioningMode.
// An example on how to create a deltahandler. // An example on how to create a deltahandler.
TM TMyDyDeleltataHaHandndleler r = = classclass((TkTkbmbmCuCuststomomDeDeltltaHaHanandldlerer)) protected protected ( ( :: ;; procedure
procedure InInsesertrtReRecocord rd varvar ReRetrtry y boboololeaeann
v
vaarr State TUpdateStatusState TUpdateStatus:: ));; oovveerrrriiddee;; (
( :: ;;
procedure
procedure DeDeleleteteReRecocord rd varvar ReRetrtry y boboololeaeann
v
vaarr State TUpdateStatusState TUpdateStatus:: ));; oovveerrrriiddee;; (
( :: ;;
procedure
procedure MoModidifyfyReRecocord rd varvar ReRetrtry y boboololeaeann
:
: ));; ;;
var
var State TUpdateStatusState TUpdateStatus overrideoverride
//
// procedure UnmodifiedRecord(var Retry:boolean;procedure UnmodifiedRecord(var Retry:boolean; var State:TUpdateStatus); override;
var State:TUpdateStatus); override;
end
end ;;
mt
mt ..AppendRecAppendRecordord((……));;
mt StartTransaction mt StartTransaction.. ;; mt mt ..EdEdit it ……..mt mt ..PoPostst;; mt Delete mt Delete.. ;; mt Rollback mt Rollback.. ;; mt mt ..AppendRecoAppendRecordrd((……));; mt
mt ..StartTransStartTransactionaction;; // First level of transaction // First level of transaction
mt
mt ..EdiEdit t ……..mt mt ..PosPostt;;
mt
mt ..StartTransStartTransactionaction;; // Second level of transaction // Second level of transaction
mt Delete
mt Delete.. ;;
mt Rollback
mt Rollback.. ;; // Back to the edited record again // Back to the edited record again
mt Rollback
mt Rollback.. ;; // Back to the original appended record // Back to the original appended record
mt
mt ..AppendRecAppendRecordord((……));;
mt StartTransaction
mt StartTransaction.. ;; // First level of transaction // First level of transaction
mt
mt ..EdEdit it ……..mt mt ..PoPostst;;
mt StartTransaction
mt StartTransaction.. ;; // Second level of transaction // Second level of transaction
mt Delete
mt Delete.. ;;
mt Commit
mt Commit.. ;; // We will keep the delete but not the // We will keep the delete but not the edited record.
edited record.
mt Rollback
mt Rollback.. ;; // Ah no.. we will revert to the original // Ah no.. we will revert to the original appended record appended record mt mt ..CheckPoinCheckPointt;; mt Undo mt Undo. . ;;
COMPONENTS
COMPONENTS
DEVELOPERS DEVELOPERS44
var
var i i ::iinntteeggeer s r s ;; ,,ssv v ::stringstring;; v v ::vvaarriiaanntt;;
begin begin := := ;; s s '''' : := = -- f foorr i i 00 ttoo FFiieellddCCoouunntt 11 ddoo begin begin : v v :==VaValulues es [[ii]];; ( ( (( )))) ::== i iff VVaarrIIssNNuulll l v v tthheenn ssvv '<NULL>''<NULL>' ( ( [[ ]].. )) ::== e ellssee iiff nnoott FFiieelldds s i i DDaattaaTTyyppe e iinn kkbbmmBBiinnaarryyTTyyppees s tthheenn ssv v vv else else := := ;; sv
sv '<Binary data>''<Binary data>'
: s s :==s s ++ssvv++' '' ';; ; ; end end (
SShhoowwMMeessssaagge e (FFoorrmmaat t (('Inserted record (%s)''Inserted record (%s)',,[[ss]]))));;
end
end ;;
procedure
procedure TMTMyDyDeleltataHaHandndleler r ..DeDeleleteteReRecocord rd ((varvar ReRetrtry y ::boboololeaean n ;; varvarStStatate e ::TUTUpdpdatateSeStatatutuss ));;
var
var i i ::iinntteeggeer s r s ;; ,,ssv v ::stringstring;; v v ::vvaarriiaanntt;;
begin begin := := ;; s s '''' : := = -- f foorr i i 00 ttoo FFiieellddCCoouunntt 11 ddoo begin begin : v v :==VaValulues es [[ii]];; ( ( (( )))) ::== i iff VVaarrIIssNNuulll l v v tthheenn ssvv '<NULL>''<NULL>' ( ( [[ ]].. )) ::== e ellssee iiff nnoott FFiieelldds s i i DDaattaaTTyyppe e iinn kkbbmmBBiinnaarryyTTyyppees s tthheenn ssv v vv := := ;; else
else svsv '<Binary data>''<Binary data>'
: s s :==s s ++ssvv++' '' ';; ; ; end end (
SShhoowwMMeessssaagge e (FFoorrmmaat t (('Deleted record (%s)''Deleted record (%s)',,[[ss]]))));;
end
end ;;
procedure
procedure TMTMyDyDeleltataHaHandndleler r ..MoModidifyfyReRecocord rd ((varvar ReRetrtry y ::boboololeaean n ;; varvarStStatate e ::TUTUpdpdatateSeStatatutuss ));;
var
var i i ::iinntteeggeer r ;; ss1 1 ,,ss2 2 ,,ssv v ::stringstring;; v v ::vvaarriiaanntt;;
begin begin := := ;; s1 s1 '''' := := ;; s2 s2 '''' : := = -- f foorr i i 00 ttoo FFiieellddCCoouunntt 11 ddoo begin begin : v v :==VaValulues es [[ii]];; ( ( (( )))) ::== i iff VVaarrIIssNNuulll l v v tthheenn ssvv '<NULL>''<NULL>' ( ( [[ ]].. )) ::== e ellssee iiff nnoott FFiieelldds s i i DDaattaaTTyyppe e iinn kkbbmmBBiinnaarryyTTyyppees s tthheenn ssv v vv := := ;; else
else svsv '<Binary data>''<Binary data>'
:
s1 s1 :==s1 s1 ++svsv++' '' ';;
:
v v :==OriOrigVagValuelues s [[ii]];; ( ( (( )))) ::== i iff VVaarrIIssNNuulll l v v tthheenn ssvv '<NULL>''<NULL>' ( ( [[ ]].. )) ::== e ellssee iiff nnoott FFiieelldds s i i DDaattaaTTyyppe e iinn kkbbmmBBiinnaarryyTTyyppees s tthheenn ssv v vv := := ;; else
else svsv '<Binary data>''<Binary data>'
: s2 s2 :==s2 s2 ++svsv++' '' ';; ; ; end end (
SShhoowwMMeessssaagge e (FFoorrmmaat t (('Modified record (%s) to (%s)''Modified record (%s) to (%s)',,[[ss2 2 ,,ss11]]))));;
end
end ;;
//procedure TMyDeltaHandler.UnmodifiedRecord(var Retry:boolean; var St
//procedure TMyDeltaHandler.UnmodifiedRecord(var Retry:boolean; var State:TUpdateStatus);ate:TUpdateStatus); //begin
//begin //end; //end;
And
And you start the deltahandler like thisyou start the deltahandler like this::
var var : : ;; myDeltaHandler TMyDeltaHandler myDeltaHandler TMyDeltaHandler begin begin :
myDeltaHamyDeltaHandler ndler :==TMyDeltaHTMyDeltaHandler andler ..CreateCreate((nilnil));;
try
try
.
mt mt .DeltaHandlDeltaHandler er ::==myDeltaHamyDeltaHandlerndler;; . . ;; mt Resolve mt Resolve finally finally .
mt mt .DeltaHandlDeltaHandlerer::==nilnil;; . . ;; myDeltaHandler Free myDeltaHandler Free ; ; end end end end ;; Issue
Issue Nr Nr 6 6 20152015 BLAISE PASCAL MAGAZINEBLAISE PASCAL MAGAZINE
COMPONENTSCOMPONENTS
DEVELOPERS DEVELOPERS
44
44
LOADING DATA
LOADING DATA
Data can be loaded into a memory table in multiple
Data can be loaded into a memory table in multiple
ways:
ways:
1.
1. InsertiInserting ng them them one one record record at at a a timetime
2.
2. Loading Loading the the data data from from another another datasetdataset
3.
3. Loading Loading the the data data from from a a filefile
As for 1, you can use the ordinary Insert/Post, or
As for 1, you can use the ordinary Insert/Post, or
AppendRecord methods.
AppendRecord methods.
As for 2, you can use:
As for 2, you can use:
mt.LoadFro
mt.LoadFromDataset(anmDataset(anotherdataseotherdataset,t,
[mtcpoStructure]);
[mtcpoStructure]);
This will make your memory table have the same
This will make your memory table have the same
fields as the anotherdataset (due to the
fields as the anotherdataset (due to the
mtcpoStructure option), and load a copy of all data
mtcpoStructure option), and load a copy of all data
from the dataset into the memory table.
from the dataset into the memory table.
A number of copy options exists:
A number of copy options exists:
mt
mtcpcpoSoStrtrucuctuturere::
Copies table structure (field definitions)
Copies table structure (field definitions) from thefrom the
source. Any field definitions you had in your local
source. Any field definitions you had in your local
memory table are removed.
memory table are removed.
mt
mtcpcpoOoOnlnlyAyActctiviveFeFieieldlds:s:
Only field definitions in the source that actually
Only field definitions in the source that actually
are represented as a true field, are
are represented as a true field, are copied.copied.
mt
mtcpcpoPoProropepertrtieies:s:
Copy over field properties like
Copy over field properties likeDisplayWidth,DisplayWidth,
DisplayLabel, Required, ReadOnly,
DisplayLabel, Required, ReadOnly,
Visible, DefaultExpression,
Visible, DefaultExpression,
Alignment, ProviderFlags, Lookup,
Alignment, ProviderFlags, Lookup,
LookupCache, LookupDataset, LookupCache, LookupDataset, LookupKeyFields, LookupResultField, LookupKeyFields, LookupResultField, KeyFields, DisplayFormat, KeyFields, DisplayFormat,
EditFormat, MaxValue, MinValue,
EditFormat, MaxValue, MinValue,
DisplayValues, TransLiterate,
DisplayValues, TransLiterate,
Precision, Currency
Precision, Currency andand BlobType. BlobType.
mt
mtcpcpoLoLooookukup:p:
Also copy lookup fields from the source dataset.
Also copy lookup fields from the source dataset.
mt
mtcpcpoCoCalalcuculalateted:d:
Also copy calculated fields from the source
Also copy calculated fields from the source
dataset.
dataset.
mt
mtcpcpoAoAppppenend:d:
Append records to the existing records in the
Append records to the existing records in the
memory table. This cant be used with
memory table. This cant be used with
mtcpoStructure
mtcpoStructure or ormtcpoProperties.mtcpoProperties.
mt
mtcpcpoFoFieieldldInIndedex:x: Copy the index position of Copy the index position of
fields to ensure field order is the same as in the
fields to ensure field order is the same as in the
original.
original.
mt
mtcpcpoDoDonontDtDisisabableleInIndedexexes:s:
Default a batch insertion is made, where indexes
Default a batch insertion is made, where indexes
are only updated after all records have been
are only updated after all records have been
copied over. However if you for example have an
copied over. However if you for example have an
index with unique constraint on a field, then you
index with unique constraint on a field, then you
might want to have your copy to stop early, if
might want to have your copy to stop early, if
there is a duplicate of that field value.
there is a duplicate of that field value.
That require that the indexes are updated on the
That require that the indexes are updated on the
fly for each record. Standard Edition will have a
fly for each record. Standard Edition will have a
larger performance penalty than
larger performance penalty thanProfessionalProfessional
Edition of kbmMemTabl
Edition of kbmMemTable for this situation.e for this situation.
mt
mtcpcpoIoIgngnororeEeErrrrorors:s:
Ignore any copy errors instead of stopping
Ignore any copy errors instead of stopping
copying.
copying.
mt
mtcpcpoLoLooookukupApAsDsDatata:a:
Copy over lookup fields a regular datafield, with
Copy over lookup fields a regular datafield, with
its matching data.
its matching data.
mt
mtcpcpoCoCalalcuculalatetedAdAsDsDatata:a:
Copy over calculated fields as a regular data field
Copy over calculated fields as a regular data field
with its calculated data.
with its calculated data.
mt
mtcpcpoSoStrtriningAgAsWsWidideSeStrtrining:g:
Assume that source ftString, ftFixedChar field
Assume that source ftString, ftFixedChar fieldss
should be created as ftWideString in your local
should be created as ftWideString in your local
memory table.
memory table.
mt
mtcpcpoWoWidideSeStrtriningUgUTFTF8:8:
If string/character/memo fields in the
If string/character/memo fields in the sourcesource
dataset do not match “wideness” of the same in
dataset do not match “wideness” of the same in
the destination dataset (
the destination dataset (your local memory tableyour local memory table),),
then automatically encode or decode to/from
then automatically encode or decode to/from
UTF8. Eg.
UTF8. Eg.
If the source dataset has field 'str1' which is a
If the source dataset has field 'str1' which is a
ftWideString
ftWideString field, while the local field, while the local
memorytable has the same field 'str1' defined as a
memorytable has the same field 'str1' defined as a
ftString
ftString field, it will UTF8 encode the data field, it will UTF8 encode the data
coming from the source field before putting it into
coming from the source field before putting it into
the destination field. Similarly if a source field is
the destination field. Similarly if a source field is
of type
of typeftString,ftString, but the destination is of type but the destination is of type
ftWideString
ftWideString then an UTF8 decoding will take then an UTF8 decoding will take
place before putting the value into the destination
place before putting the value into the destination
field. The same takes place with
field. The same takes place with
ftMemo/ftWideMemo
ftMemo/ftWideMemo and and
ftFixedChar/ftWideFixedChar
ftFixedChar/ftWideFixedChar..
If you already have an existing field structure in
If you already have an existing field structure in
your local memory table, and want to copy fields
your local memory table, and want to copy fields
from a source dataset, where the field names do
from a source dataset, where the field names do
not match, you can take advantage of field name
not match, you can take advantage of field name
mapping.
mapping.
Eg.
Eg.
This is telling kbmMemTable that the local field
This is telling kbmMemTable that the local field
named str1 is called str_1 in the source table etc.
named str1 is called str_1 in the source table etc.
As for option 3, loading from a file, you can use:
As for option 3, loading from a file, you can use:
mt mt.L.LoaoadFdFroromFmFilileVeViaiaFoFormrmatat(('somefilename','somefilename', someformatinstance) someformatinstance);; mt LoadFromDataset anotherdataset mt LoadFromDataset anotherdataset.. (( ,, [ []],,'str1=str_1;int2=int_2''str1=str_1;int2=int_2'));; Issue
Issue Nr Nr 6 6 20152015 BLAISE PASCAL MAGAZINEBLAISE PASCAL MAGAZINE
45
45
COMPONENTSCOMPONENTS
DEVELOPERS DEVELOPERS
44
Its practical if the data of field fld1 is required to
Its practical if the data of field fld1 is required to
be quickly accessible in your string list. In this
be quickly accessible in your string list. In this
example, s will only contain the value of fld2. If
example, s will only contain the value of fld2. If
you need the field value both as an object and as
you need the field value both as an object and as
part of the string, you can include it twice in your
part of the string, you can include it twice in your
field list.
field list.
Eg.
Eg. 'fld1;fld1;fld2'.'fld1;fld1;fld2'.
A different extraction method is
A different extraction method isGetRowsGetRows which which
returns requested fields as an array of an array of
returns requested fields as an array of an array of
variant.
variant.
This will return an array of variant containing an
This will return an array of variant containing an
array of variant of size 1, with the contents of the
array of variant of size 1, with the contents of the
field with
field withFieldNo=1FieldNo=1..
Eg.
Eg. v[0,0]v[0,0] is the value of the first field of the firstis the value of the first field of the first
record.
record.
Since we specified to
Since we specified to ask for kbmGetRowsRestask for kbmGetRowsRest
number of records, starting with
number of records, starting with
kbmBookMarkFirst,
kbmBookMarkFirst, then we are essentially then we are essentially
asking for all records. If we wanted to start from
asking for all records. If we wanted to start from
another place in the record set, you should
another place in the record set, you should
provide a
provide aTBookmarkTBookmark value for that place. value for that place.
That is created by navigating to the record, then
That is created by navigating to the record, then
use the Bookmark function to obtain a bookmark
use the Bookmark function to obtain a bookmark
for exactly that place in the record set.
for exactly that place in the record set.
And by providing a number instead of
And by providing a number instead of
kbmGetRowsRest,
kbmGetRowsRest, you can limit the number of you can limit the number of
records returned to that particular count.
records returned to that particular count.
The last argument of
The last argument ofGetRows,GetRows, can either be a can either be a
field number, a field name or an array of field
field number, a field name or an array of field
numbers or an array of field names.
numbers or an array of field names.
someformatinstance
someformatinstance is an instance of a stream is an instance of a stream
format component.
format component.kbmMemTablekbmMemTable comes with comes with
two,
two,TkbmMemBinaryStreamFormatTkbmMemBinaryStreamFormat and and
TkbmMemCSVStreamFormat.
TkbmMemCSVStreamFormat.
The binary stream format class stores data
The binary stream format class stores data
compactly and efficiently, and is giving the
compactly and efficiently, and is giving the
fastest performance. However the CSV stream
fastest performance. However the CSV stream
format class allows you to read in (
format class allows you to read in (and write outand write out))
comma separated formatted data, for easy
comma separated formatted data, for easy
integration with other external systems.
integration with other external systems.
kbmMW (
kbmMW (our middleware productour middleware product) comes with) comes with
additional stream formatters for XML and
additional stream formatters for XML and JSON.JSON.
Each stream format instance have a number of
Each stream format instance have a number of
flags that can be set, to tell how it's supposed to
flags that can be set, to tell how it's supposed to
handle the reading or writing of data, but that is
handle the reading or writing of data, but that is
a story for another time.
a story for another time.
sf
sf ::==TkbmMemCSTkbmMemCSVStreamForVStreamFormat mat ..CreateCreate((nilnil));;
try try . mmt t .LLooaaddFFrroommFFiilleeVViiaaFFoorrmmaat t (('.\mydata.csv''.\mydata.csv',,ssff)) finally finally . . ;; sf Free sf Free end end ;; EXTRACTING DATA EXTRACTING DATA
A number of methods exist for easily extract data
A number of methods exist for easily extract data
from a memory table.
from a memory table.
mt
mt.E.Extxtraractct('('flfld1d1;f;fldld2'2',s,slDlDatata)a);;
This one will extract the fields fld1 and fld2 for all
This one will extract the fields fld1 and fld2 for all
records to a
records to aTStringsTStrings instance instance (TStringList(TStringList
typically)
typically) that you will have to create beforehand. that you will have to create beforehand.
If the optional
If the optionalAFormatAFormat string is given, e string is given, each lineach line
in
inTStringsTStrings will be formatted according to that will be formatted according to that
format. If none is given, then all field values for a
format. If none is given, then all field values for a
record will be separated by a space.
record will be separated by a space.
The above example will thus put a space between
The above example will thus put a space between
the value of fld1 and fld2 for each record/line.
the value of fld1 and fld2 for each record/line.
mt.Extract(
mt.Extract('fld1;fld2''fld1;fld2',slData,'%s,slData,'%s=%s');=%s');
This will put an equal
This will put an equal
sign between the value
sign between the value
of fld1 and fld2.
of fld1 and fld2.
It is also possible to specify that the first field (in
It is also possible to specify that the first field (in
the following case fld1) should be stored as an
the following case fld1) should be stored as an
object for the text line in the strings list.
object for the text line in the strings list.
mt.Extract('fld1;fld2',slData,'',true);
mt.Extract('fld1;fld2',slData,'',true);
Then you can access that value by:
Then you can access that value by:
var
var v variantv variant:: ;;
begin
begin
… …
:
v v :==TkbmVariaTkbmVariantObject ntObject ((slData slData ..Objects Objects [[ii]] ).
).ValueValue;;
:
s s :==slDaslData ta ..StriStrings ngs [[ii]];; …
…
end
end ;;
var
var v variantv variant:: ;;
begin
begin
:
:== .. (( ,, ,, ));;
v
v mt mt GetRGetRows ows kbmGkbmGetRoetRowsRewsRest st kbmBkbmBookMookMarkFarkFirstirst 11
end
end ;;
v
v ::==mt mt ..GetRows GetRows ((kbmGetRowkbmGetRowsRest sRest ,, kbmBookMakbmBookMarkFirst rkFirst ,,VarArrayOVarArrayOff (('f'fldld1'1',,'f'fldld2'2'))));;
Issue
Issue Nr Nr 6 6 20152015 BLAISE PASCAL MAGAZINEBLAISE PASCAL MAGAZINE
COMPONENTSCOMPONENTS
DEVELOPERS DEVELOPERS
44
46
STATISTICS
STATISTICS
kbmMemTable contains a number of
kbmMemTable contains a number of
functions to allow very fast grouping and
functions to allow very fast grouping and
calculation of statistical values for your
calculation of statistical values for your
data. Returning a sum of fld1 for all records
data. Returning a sum of fld1 for all records
visible in the current index.
visible in the current index.
v will contain the sum of fld1 for all records in the
v will contain the sum of fld1 for all records in the