blaisepascalmagazine 44 uk

Upload: thotsaphon-chaiyachet

Post on 07-Jan-2016

57 views

Category:

Documents


14 download

DESCRIPTION

O V E R V I E W O F D E L P H I T O D E L P H I H I S T O R YE U C L I D E SA N A G E P U Z Z L EB Y D A V I D D I R K S EA R D U I N O : T H E V I S U I N O P R O J E C T - P A R T 4I N T E R N E T O F T H I N G S - WI T H A R D U I N O A N D D E L P H IU S E E T H E R N E T S H I E L D , P R O G R A M I T W I T H V I S U I N O ,C O N N E C T F R O M A D E L P H I A P P L I C AT I O NO V E R T H E L O C A L N E T W O R K O R I N T E R N E TB Y B O I A N M I T O VD A T A B A S E WO R K B E N C H 5T H E S W I S S A R M Y K N I F E F O R D ATA B A S E SB Y P E T E R V A N D E R S M A NT I P S A N D T R I C K S WI T H K B M M E M T A B L EB Y K I M M A D S E N

TRANSCRIPT

  • PRINTED ISSUE PRICE 15.00

    DOWNLOAD ISSUE PRICE 7 .50

    BLAISE PASCAL MAGAZINEBLAISE PASCAL MAGAZINEBLAISE PASCAL MAGAZINE 444444

    D E L P H I, L A Z A R U S, O X Y G E N E, S M A R T M O B I L E,

    A N D P A S C A L R E L A T E D L A N G U A G E S

    A N D R O I D, I O S, M A C , W I N D O W S & L I N U X

    OVERVIEW OF DELPHI TO DELPHI HISTORY

    EUCLIDES

    AN AGE PUZZLE

    BY DAVID DIRKSE

    ARDUINO: THE VISUINO PROJECT - PART 4

    INTERNET OF THINGS - WITH ARDUINO AND DELPHI

    USE ETHERNET SHIELD, PROGRAM IT WITH VISUINO,

    CONNECT FROM A DELPHI APPLICATION

    OVER THE LOCAL NETWORK OR INTERNET

    BY BOIAN MITOV

    DATABASE WORKBENCH 5

    THE SWISS ARMY KNIFE FOR DATABASES

    BY PETER VAN DER SMAN

    TIPS AND TRICKS WITH KBMMEMTABLE

    BY KIM MADSEN

  • CONTENTS

    BLAISE PASCAL MAGAZINEBLAISE PASCAL MAGAZINE

    Articles

    D E L P H I, L A Z A R U S, S M A R T M O B I L E S T U D I O,

    A N D P A S C A L R E L A T E D L A N G U A G E S

    F O R A N D R O I D, I O S, M A C, W I N D O W S & L I N U X

    Issue Nr 6 2015 BLAISE PASCAL MAGAZINE

    444444

    OVERVIEW OF DELPHI TO DELPHI HISTORY PAGE 6

    EUCLIDES PAGE 7

    AN AGE PUZZLE PAGE 8

    BY DAVID DIRKSE

    ARDUINO: THE VISUINO PROJECT - PART 4

    INTERNET OF THINGS - WITH ARDUINO AND DELPHI

    USE ETHERNET SHIELD, PROGRAM IT WITH VISUINO,

    CONNECT FROM A DELPHI APPLICATION

    OVER THE LOCAL NETWORK OR INTERNET

    BY BOIAN MITOV PAGE 12

    DATABASE WORKBENCH 5

    THE SWISS ARMY KNIFE FOR DATABASES

    BY PETER VAN DER SMAN PAGE 28

    TIPS AND TRICKS WITH KBMMEMTABLE

    BY KIM MADSEN PAGE 39

    Advertisers

    BETTER OFFICE

    COMPONENTS 4 DEVELOPERS 48

    COMPUTER MATH & GAMES 4/5

    DANIEL TETI DELPHI COOKBOOK 11

    EVERS 36

    NEW BLAISE LIBRARY 38

    PASCON DELPHI 37

    UPSCENE 35

    VISUINO MITOV 27

    Publisher: Foundation for Supporting the Pascal Programming Language in collaboration with the Dutch Pascal User Group (Pascal Gebruikers Groep)

    Stichting Ondersteuning Programmeertaal Pascal

    2

  • All material published in Blaise Pascal is copyright SOPP Stichting Ondersteuning Programeertaal Pascal unless otherwise noted and may

    not be copied, distributed or republished without written permission. Authors agree that code associated with their articles will be made

    available to subscribers after publication by placing it on the website of the PGG for download, and that articles and code will be placed on

    distributable data storage media. Use of program listings by subscribers for research and study purposes is allowed, but not for commercial

    purposes. Commercial use of program listings and code is prohibited without the written permission of the author.

    Copyright notice

    Editors

    Peter Bijlsma, W. (Wim) van Ingen Schenau, Rik Smit,

    Correctors

    Howard Page-Clark, James D. Duff

    Trademarks

    All trademarks used are acknowledged as the property of their respective owners.

    Caveat Whilst we endeavour to ensure that what is published in the magazine is correct, we cannot accept responsibility for any errors or omissions.

    If you notice something which may be incorrect, please contact the Editor and we will publish a correction where relevant.

    Subscriptions ( 2013 prices )

    1: Printed version: subscription 65.-- Incl. VAT 6 % (including code, programs and printed magazine,

    10 issues per year excluding postage).

    2: Electronic - non printed subscription 45.-- Incl. VAT 21% (including code, programs and download magazine)

    Subscriptions can be taken out online at www.blaisepascal.eu or by written order, or by sending an email to [email protected]

    Subscriptions can start at any date. All issues published in the calendar year of the subscription will be sent as well.

    Subscriptions run 365 days. Subscriptions will not be prolonged without notice. Receipt of payment will be sent by email.

    Subscriptions can be paid by sending the payment to:

    ABN AMRO Bank Account no. 44 19 60 863 or by credit card: Paypal

    Name: Pro Pascal Foundation-Foundation for Supporting the Pascal Programming Language (Stichting Ondersteuning Programeertaal Pascal)

    IBAN: NL82 ABNA 0441960863 BIC ABNANL2A VAT no.: 81 42 54 147 (Stichting Programmeertaal Pascal)

    Subscription department Edelstenenbaan 21 / 3402 XA IJsselstein, The Netherlands / Tel.: + 31 (0) 30 890.66.44 / Mobile: + 31 (0) 6 21.23.62.68

    [email protected]

    Editor - in - chief

    Detlef D. Overbeek, Netherlands Tel.: +31 (0)30 890.66.44 / Mobile: +31 (0)6 21.23.62.68

    News and Press Releases email only to [email protected]

    Authors - Christian name in alphabethical order

    A Andrea Raimondi ,

    B Peter Bijlsma, Dmitry BoyarintsevStephen Ball,

    C Marco Cant, Michal Van Canneyt,

    D David Dirkse, Daniele Teti

    F Bruno Fierens

    G Primo Gabrijeli, Mattias Gaertner

    H Fikret Hasovic

    J Cary Jensen

    L Wagner R. Landgraf, Sergey Lyubeznyy

    K Max Kleiner

    M Kim Madsen, Felipe Monteiro de Cavalho

    N Jeremy North,

    O Inoussa Ouedraogo

    P Howard Page-Clark,

    S Rik Smit, Bob Swart,

    Z Siegfried Zuhr

    Stephen Ball

    http://delphiaball.co.uk

    @DelphiABall

    Peter Bijlsma

    -Editor peter @ blaisepascal.eu

    Michal Van Canneyt,

    michael @ freepascal.org

    Marco Cant

    www.marcocantu.com

    marco.cantu @ gmail.com

    David Dirkse

    www.davdata.nl

    E-mail: David @ davdata.nl

    Bruno Fierens

    www.tmssoftware.com

    bruno.fierens @ tmssoftware.com

    Primo Gabrijeli

    www.

    primoz @ gabrijelcic.org

    Cary Jensen

    www.jensendatasystems.com

    http://caryjensen.blogspot.nl

    Wagner R. Landgraf

    wagner @ tmssoftware.com

    Kim Madsen

    www.component4developers

    Peter van der Sman

    [email protected]

    Jeremy North

    jeremy.north @ gmail.com

    Benno Evers

    b.evers

    @everscustomtechnology.nl

    Detlef Overbeek - Editor in Chief

    www.blaisepascal.eu

    editor @ blaisepascal.eu

    Howard Page Clark

    E-mail: hdpc @ talktalk.net

    Rik Smit

    rik @ blaisepascal.eu

    Bob Swart

    www.eBob42.com

    Bob @ eBob42.com

    Max Kleiner

    www.softwareschule.ch

    [email protected]

    Please note: extra space characters have been deliberately added around the @ symbol in

    these email addresses, which need to be removed if you use them.

    editor @ blaisepascal.eu

    Issue Nr 5 2015 BLAISE PASCAL MAGAZINE

    Daniele Teti

    www.danieleteti.it

    [email protected]

    Andrea Raimondi

    John Kuiper

    [email protected]

    Wim Van Ingen Schenau

    -Editor

    wisone @ xs4all.nl

    3

  • BLAISE PASCAL MAGAZINEis proud to announce the first edition of David Dirkses book:

    COMPUTER & MATH

    IN GAMES PASCAL

    DAVID DIRKSEpresales at

    www.blaisepascal.eu/DavidDirkse/ComputerMath_Games.html

    procedure ;

    var

    begin

    := for to doi 1 9

    begin

    ;end

    end;

  • DAVID DIRKSEs

    www.blaisepascal.eu/DavidDirkse/ComputerMath_Games.html

    A book printed in full color, sewn back bound with a hard

    cover. Quality first. A fully indexed PDF file is included.

    The book contains 87 chapters, 53 projects with source

    code and compiled programs (exe).

    All of these projects you can download at our special

    website www.blaisepascal.eu

    The book is highly educational and suitable for beginners

    as well as for professionals.

    Play board games, solve puzzles, operate a vintage

    mechanical calculator, Produce 3-dimensional computer

    art, generate lists of prime numbers, explore and draw

    any mathematical function.

    Solve systems of equations, calculate the area of complex

    polygons.

    Draw lines, circles and ellipses.

    Resize, rotate, compress digital images.

    Design your own font, generate and reduce Truth Tables

    from Boolean algebra.

    And more important: understand how it all works!

    For the games, winning strategies are explained.

    For puzzles the search algorithm.

    For all projects: the math behind is thoroughly discussed.

    The Delphi 3 7 (or later) source code is available

    together with full explanation. Most of the projects can

    be done with FPC Lazarus as well.

    Pascal is the most educative, easy to learn and only

    language available for several operating systems like

    Windows, Linux, Mac and Android.

    It is a great programming language

    COMPUTER & MATH

    IN GAMES PASCAL

  • Page 9

    WATER CLOCK - CHINA - BEGINNING OF TIME (BC 4000)

    Some authors claim that water clocks appeared in China

    as early as 4000 BC

    DELPHI

    The cult of Apollo at

    Delphi probably

    dates back to

    the 700s B . C .,

    Plato in Classical Attic;

    428/427 or 424/423 348/347 BC)

    was a philosopher, as well as mathematician,

    in Classical Greece.

    Pythagoras Philosopher

    Pythagoras of Samos was an

    Ionian Greek philosopher, mathematician,

    and founder of the religious movement

    called Pythagoreanism.

    Born: 571 - 495 BC,

    Archimedes Mathematician

    Archimedes of Syracuse was an Ancient

    Greek mathematician, physicist, engineer,

    inventor, and astronomer.

    He is regarded as one of the leading scientists

    in classical antiquity. Wikipedia

    Born: 287 - 212 BC, Syracuse, Italy

    Thales Philosopher

    Thales of Miletus was a pre-Socratic Greek philosopher

    from Miletus in Asia Minor and one of the

    Seven Sages of Greece. Many, most notably Aristotle,

    regard him as the first philosopher in the Greek tradition.

    Born: 624 BC - 546

    Euclid Mathematician

    Born Mid-4th century BC - 3rd century BC

    Residence Alexandria, Hellenistic Egypt

    Fields Mathematics Known for

    Euclidean geometry / Euclid's Elements

    Euclidean algorithm

    Roman Empire 700 BC

    Decay of the Roman Empire 500

    Building of Europe

    Babbage Difference Engine No. 2

    OVERVIEW OF DELPHI TO DELPHI HISTORY

    Building of France 5852 BC

    Building of Spain 912 and Portugal 800

    Discovery of Amerca by the Vikings 990 - 1050

    Discovery of America by Columbus

    Columbus led his three ships - the Nina,

    the Pinta and the Santa Maria -

    out of the Spanish port of Palos on August 3, 1492.

    Blaise Pascal (19 June 1623 19 August 1662)

    was a French mathematician,

    physicist, inventor, writer and Christian philosopher.

    creates the first calculators

    Blaise Pascal starts to gamble - result first statistics

    Niklaus Wirthborn February 15, 1934 He is a Swiss

    computer scientist, best known for

    designing several programming languages,

    including Pascal, and for pioneering several

    classic topics in software engineering.

    Windows

    Lisa - Pascal was a Pascal implementation for the Apple Lisa workstation. It was an extension of the earlier Apple Pascal for Apple II machines,

    but generated object code for 68000 processors that had to be linked

    against the required libraries in the Lisa OS workshop.

    Lisa Pascal laid the foundation for the development of Clascal and Mac Pascal

    the first implementations of Object Pascal.

    Turbo Pascal

    Developer(s) Anders Hejlsberg while

    working at Borland

    Operating system CP/M, CP/M-86, DOS,

    Windows 3.x, Macintosh

    Platform 8080/Z80, 8085, x86

    DELPHI XE8

    DELPHI 7 released in August 2002

    DELPHI released February 14, 1995

    Embarcadero Technologies in 2008.

    Codegear Delphi 2007.

    Charles Babbage - mathematician conceived of the first programmable computer in the 1830s

    Babbage never built his Difference Engine

    - a mechanical calculator with thousands of parts -

    because of cost overruns and political disagreements,

    but the inventor passed on plans for its completion,

    and in 1991, the Science Museum in London actually

    built it (the printing component was finished in 2000).

    As suspected, it actually works.

    The roots of Turbo Pascal v1.0 started in Denmark. The first step,

    in 1981, was the Blue Label Software Pascal Compiler - BLS Pascal

    Compiler v1.2, copyright 1981 by Poly-Data microcenter ApS,

    Strandboulvarden 63, DK 2100 Copenhagen - written by Anders

    Hejlsberg for the NASCOM kit computer.

    On February 8, 2006 Borland announced that it was

    looking for a buyer for its IDE and database line of products,

    including Delphi, to concentrate on its ALM line. On November

    14, 2006 Borland transferred the development tools group to

    an independent subsidiary company named CodeGear,

    instead of selling it. Borland sold CodeGear to Embarcadero

    Technologies in 2008. Embarcadero retained the CodeGear

    division created by Borland to identify its tool and database

    offerings, but identified its own database tools under the

    DatabaseGear name.

    Difference Engine No. 1, portion,1832

    ISSUE 40

    IN THIS ISSUE (43)

  • Issue Nr 6 2015 BLAISE PASCAL MAGAZINE 7

    Euclid (300 BC), sometimes called

    Euclid of Alexandria to distinguish him

    from Euclid of Megara, was a Greek

    mathematician, often referred to as the

    "Father of Geometry". He was active in

    Alexandria during the reign of Ptolemy

    I (323283 BC). His Elements is one of

    the most influential works in the history

    of mathematics, serving as the main

    textbook for teaching mathematics

    (especially geometry) from the time of

    Very few original references to Euclid survive, so little

    is known about his life. The date, place and

    circumstances of both his birth and death are unknown

    and may only be estimated roughly relative to other

    figures mentioned alongside him. He is rarely

    mentioned by name by other Greek mathematicians

    from Archimedes onward, who usually call him "the

    author of Elements".The few historical references to

    Euclid were written centuries after he lived, by Proclus

    c. 450 AD and Pappus of Alexandria c. 320 AD

    Proclus introduces Euclid only briefly in his

    Commentary on the Elements. According to Proclus,

    Euclid belonged to Plato's "persuasion" and brought

    together the Elements, drawing on prior work by

    several pupils of Plato. Proclus believes that Euclid is

    not much younger than these, and that he must have

    lived during the time of Ptolemy I because he was

    mentioned by Archimedes (287212 BC). Although the

    apparent citation of Euclid by Archimedes has been

    judged to be an interpolation by later editors of his

    works, it is still believed that Euclid wrote his works

    before those of Archimedes.

    Proclus later retells a story that, when Ptolemy I asked

    if there was a shorter path to learning geometry than

    Euclid's Elements, "Euclid replied there is no royal

    road to geometry. In the only other key reference to

    Euclid, Pappus briefly mentioned in the fourth century

    that Apollonius "spent a very long time with the pupils

    of Euclid at Alexandria 247222 BC.

    Euclidean geometry is a mathematical system

    attributed to the Alexandrian Greek mathematician

    Euclid, which he described in his textbook on

    geometry: the Elements. Euclid's method consists in

    assuming a small set of intuitively appealing axioms,

    and deducing many other propositions (theorems)

    from these. Although many of Euclid's results had

    been stated by earlier mathematicians, Euclid was the

    first to show how these propositions could fit into a

    comprehensive deductive and logical system. The

    Elements begins with plane geometry, still taught in

    secondary school as the first axiomatic system and the

    first examples of formal proof. It goes on to the solid

    geometry of three dimensions. Much of the Elements

    states results of what are now called algebra and

    number theory, explained in geometrical language.

    For more than two thousand years, the adjective

    "Euclidean" was unnecessary because no other sort of

    geometry had been conceived. Euclid's axioms

    seemed so intuitively obvious (with the possible

    exception of the parallel postulate) that any theorem

    proved from them was deemed true in an absolute,

    often metaphysical, sense. Today, however, many

    other self-consistent non-Euclidean geometries are

    known, the first ones having been discovered in the

    early 19th century. An implication of Albert Einstein's

    theory of general relativity is that physical space itself

    is not Euclidean, and Euclidean space is a good

    approximation for it only where the gravitational field

    is weak.

    Euclidean geometry is an example of synthetic

    geometry, in that it proceeds logically from axioms to

    propositions without the use of coordinates. This is in

    contrast to analytic geometry, which uses coordinates.

    its publication until the late 19th or early 20th century.

    In the Elements, Euclid deduced the principles of what is

    now called Euclidean geometry from a small set of

    axioms. Euclid also wrote works on perspective, conic

    sections, spherical geometry, number theory and rigor.

    Because the lack of biographical information

    is unusual for the period (extensive

    biographies are available for most significant

    Greek mathematicians for several centuries

    before and after Euclid), some researchers

    have proposed that Euclid was not, in fact, a

    historical character and that his works were

    written by a team of mathematicians who took

    the name Euclid from the historical character

    Euclid of Megara.

    EUCLIDES

  • Issue Nr 6 2015 BLAISE PASCAL MAGAZINE

    8

    AN AGE PUZZLE PAGE 1/4BY DAVID DIRKSE

    On new year of the year 1997 mr. Black, a math

    teacher, meets his former student White. White

    remembers Blacks fascination for numbers and

    greets him with: my age is equal to the sum of the

    digits of my year of birth.

    Black thinks for a while and then answers:

    congratulations on your birthday.

    QUESTIONS:

    1. How Black may know that it is White's

    birthday?

    2. What is White's age?

    SOLUTION

    If Peter was born in 2000 and we live in

    the year 2015 there are two possibilities:

    Peter is 14 years old and his birthday

    still has to come or Peter 15 years old

    and his birthday is passed.

    The solution may be found by checking

    all possible years and calculating the

    sum of the birthyear digits. Test for

    digitsum = current year birth year ...(-

    1 if anniversary still has to come)

    This means a lot of work, so better we

    write a program to do the job.

    THE PROGRAM

    There may be more solutions. We choose

    to calculate them all and store them in a

    list. Thereafter the solutions are

    displayed on the screen.

    For a solution we define the data type:

    The solutions are displayed in a paintbox, see

    picture.

    We notice columns for the solution number, the

    year of birth, the age and the answer of the

    question anniversary passed?.

    Pressing the search button starts the search

    process.

    Also pressing the return key after the current

    year starts the search.

    The text on the form is placed in Tlabel

    components.

    On the bottom of the form at full width there is

    a statictext component for messages.

    The picture below shows : 4 solutions found.

    There are three reasons to make a function or a

    procedure. First is the case of common code that

    is needed at multiple places of the main program.

    This reduces the total code.

    The second reason is clearity. We place specific

    code apart for readability.

    For this reason we made a function to sum the

    birthyear digits.

    And these global variables:

    Thisyear comes from a TEdit component

    (this year) where the current year was typed.

    Solutions is an array[1..maxsolution] of type

    TSolution.

    SolutionNr is the number of stored solutions.

    This value is 0 if no solution exists.

    Maxsolution is a constant set at 20.

    Tsolution = record

    : ;birthyear word

    : ;age byte

    : ;birthdaypassed boolean

    ;end

    var : ;thisyear word

    : [ ] ;solutions maxsolution Tsolutionarray of1..

    : ; solutionNr byte

  • 9MaxSolution is a constant set to 20, the space in

    the solutions array.

    Which saves typing. Otherwise we had to add

    solutions[solutionNr]. before

    birthyear, age. Now this is done by Delphi.

    The procedure ShowSolutions:

    function ( : ) : ;sumdigits year word byte

    var string : ;s

    : ;i byte

    begin

    := ( );s inttostr year

    := ;result 0

    := ( ) := + ( [ ])- ( );for to doi length s result result ord s i ord1 '0'

    end;

    Ord('0') is 48, the ASCII code of digit 0.

    So ord('8') ord('0') = 8.

    Without -ord('0') we would get 56.

    THE SEARCH PROCESS

    In procedure searchBrtClick, called by the search

    button, we notice following local variables:

    var : ;digitsum byte

    : ;birthyear word

    variabele birthyear runs from

    startyear...thisyear.

    startyear is a constant set to 1900.

    Digitsum is the sum of the digits of

    birthyear.

    Before the search starts two checks are made:

    1. the current year must be defined

    2. the current year must be equal or bigger than

    startyear.

    Then solutionNr is set to zero.

    All values of birthyear are checked.

    If the test yields true, age (=digitsum) and

    anniversary passed is added to the solutions

    array. This program loop looks like:

    for to do := birthyear startyear thisyear

    begin

    := ( );digitsum sumdigits birthyear

    = - if thendigitsum thisyear birthyear

    ( , , );savesolution digitsum birthyear true

    = - - if thendigitsum thisyear birthyear 1

    ( , , );savesolution digitsum birthyear false

    ; end //for

    The procedure SaveSolution:

    procedure ( , : ; : );SaveSolution ag by word bp boolean

    //ag:age; by:birthyear; bp:birthday passed

    begin

    ( );inc solutionNr

  • Issue Nr 6 2015 BLAISE PASCAL MAGAZINE10

    Why all this preset constants? Why not using the

    values directly? Sure we could. But using

    constants is smarter because they make future

    changes much more easy. Say we want to change

    the startyear. Without the constant definition we

    would have to change all places where the

    constant (1900) was used. But defined as a

    constant we only need to change the constant

    value once to be effective in all places in the

    program.

    PROCEDURE BEFORE CALLED

    CLEARPAINTBOX.

    This procedure erases the paintbox by painting

    the canvas white. (for this color we could have used a

    constant as well)

    procedure ;clearpaintbox

    begin

    . with doform1 PaintBox1

    with docanvas

    begin

    . := ;brush Style bsSolid

    . := ;brush color $ffffff

    ( ( , , , ));fillrect rect width height0 0

    ;end

    end;

    The paintbox has properties width, height and

    canvas. By not using with

    form1.paintbox1.canvas but the separation

    with form1.paintbox1 do with canvas do, we may

    use both the canvas and the paintbox properties

    without the name prefixes. Canvas property

    brush takes care of background coloring.

    Style is a property of the brush. If we write

    brush.style := bsClear the fillrect does nothing,

    the brush is turned off. Fillrect( r ) paints

    rectangle r of the paintbox in the color

    brush.color. r is of type Trect. Function rect

    (defined inside Delphi) makes a Trect from

    coordinates.

    See picture:

    We notice that the width occupies left ...

    right-1 and the height is from top to

    bottom-1. Width = right left.

    Height = bottom top.

    SETTINGS

    In the TEdit component YearEdit we enter

    the current year. Property maxlength of

    YearEdit is set to 4. This prevents entering

    more than four digits.

    The event YearEditKeyPress points to a

    procedure of this name. Reason is to allow only

    the digits 0..9 together with backspace for

    procedure . ( : ; TForm1 yeareditKeyPress Sender TObject

    var : );Key Char

    begin

    ( [ .. , ]) := ;if not in thenkey key'0' '9' #08 #0

    end;

    8 is the ASCII code of the backspace key.

    Prefix # denotes a following character code.

    The data between [] is of the SET datatype.

    We want to start the search as well by pressing

    the return key after the current year.

    The return code is catched before it reaches the

    Tedit. This is done by setting the Tform

    property KeyPreview to true and defining the

    event FormKeyDown.

    procedure . ( : ; TForm1 FormKeyDown Sender TObject

    var : ; : );Key Word Shift TShiftState

    // starts search

    begin

    = if thenkey VK_RETURN

    begin

    := ;key 0

    ( );searchBtnClick self

    ;end

    end;

    VK_RETURN is a predifined Delphi constant

    representing the return key.

    NOTE: key now is of the type word, not char.

    Procedure searchBtnClick is called

    with Form1 (self) as sender.

    For more details please refer to the source code.

    FINALLY

    With the help of this program the reader may

    solve the puzzle without doing the arithemetic

    himself. Now it becomes clear why Black is sure

    today is White's birthday.

    Other, more difficult, questions would be birth

    years that have zero or multiple solutions.

    This would require some extensions of the

    program.

    Have fun!

    AN AGE PUZZLE PAGE 3/4

  • 50 hands-on recipes to master the power of Delphi for

    cross-platform and mobile development on Windows,

    Mac OS X, Android, and iOS

    Daniele Teti

    Quick answers to common problems

    Delphi Cookbook

    See our special offer:

    if you take out a subscription

    for two years the book

    will cost you only 10,00

    http://www.blaisepascal.eu/daniele_teti_book/DanieleTeti.html

    OICH EC SR

    OT

    ID

    E

    A

    MAZIN

    G

    BLAISE PASCAL

    MAGAZINE

    30,00

    including VAT

    39

    including

    the

    printed

    book,

    ebook

    and shipping

  • Issue Nr 6 2015 BLAISE PASCAL MAGAZINE12

    BY BOIAN MITOV

    In the previous articles, you learned how to

    program Arduino using Visuino, and how to

    communicate with it using USB simulated serial

    port from your Delphi code. This opens a lot of

    interesting possibilities for collecting and

    processing live data, but the direct USB

    connection imposes some limitations. What if you

    want to collect data from many sensors spread

    over large area? Or what if you want to

    communicate with remote sensors over Internet?

    The basic Arduino UNO does not have built in

    network adapter, but there is Ethernet shield

    available for it. In addition many of the more

    advanced Arduino boards and their clones come

    with WiFi or wired Ethernet built in.

    There are also cheap and simple ESP8266 WiFi

    modules that can be connected to the Arduino, so

    networking Arduinos is routinely done.

    In this article you will learn how to setup Arduino

    to use Ethernet Shield, how to program it with

    Visuino, and how to connect to it from a Delphi

    application over the local network or Internet.

    Before you start, you will need to install Ethernet

    Shield on the Arduino. This is fairly easy. Just

    snap it on top of the board as shown in the

    picture.

    Add Ethernet Shield:

    Next you need to specify the MAC address for

    the shield. You can use a MAC address generator,

    or one of the MAC addresses from the Arduino

    tutorials. Here I use DE-AD-BE-EF-FE-ED:

    You also will need to install CommunicationLab,

    PlotLab and InstrumentLab from Mitov

    Software. CommunicationLab is not officially

    released yet, but prerelease builds are available

    on request. You can also easily modify the

    examples in this article not to use PlotLab or

    InstrumentLab.

    First you will create a simple Arduino server.

    Start Visuino. Click on the Down arrow button in

    the top right corner of the Arduino component,

    and from the menu select Add Shields... :

    ARDUINO: THE VISUINO PROJECT - PART 4 PAGE - 1/15

    INTERNET OF THINGS WITH ARDUINO AND DELPHI

  • 13

    Set the IP address for the Arduino

    as example 192.168.0.55:

    And set the Enabled property of the IPAddress

    to True so the IP address will be used when

    Arduino starts:

    Once the Ethernet Shield is configured, you can

    add one or more TCP/IP Client, TCP/IP Server,

    or UDP sockets to it. Click on the ... button

    after the Sockets to add a socket:

    Issue Nr 6 2015 BLAISE PASCAL MAGAZINE

    Add TCP/IP Server socket:

    Set the UseDHCP to false, so Arduino will

    work with a fixed IP address:

    ARDUINO: THE VISUINO PROJECT - PART 4 PAGE - 2/15

    INTERNET OF THINGS WITH ARDUINO AND DELPHI

  • 6 Issue Nr 6 2015 BLAISE PASCAL MAGAZINE14

    Set the Socket Port property to 8080:

    To generate some test data from Arduino, you

    can use a Sine Generator as shown here, or

    you can use any other source of Analog data,

    or one of the Analog channels:

    ARDUINO: THE VISUINO PROJECT - PART 4 PAGE - 3/15

    INTERNET OF THINGS WITH ARDUINO AND DELPHI

  • Issue Nr 6 2015 BLAISE PASCAL MAGAZINE 15

    Connect the data source to the Input Pin of the

    Server Socket:

    Press F9 to generate the Arduino

    Sketch and open the Arduino IDE:

    ARDUINO: THE VISUINO PROJECT - PART 4 PAGE - 4/15

    INTERNET OF THINGS WITH ARDUINO AND DELPHI

  • Issue Nr 6 2015 BLAISE PASCAL MAGAZINE16

    Click on the Upload button to compile and

    upload the sketch:

    The simplest way to see if the Arduino project is

    working is to open a web browser and enter the

    Arduino IP address, and socket number

    192.168.0.55:8080 . You should see the data

    appearing in the browser, in this case Chrome:

    ARDUINO: THE VISUINO PROJECT - PART 4 PAGE - 5/15

    INTERNET OF THINGS WITH ARDUINO AND DELPHI

  • 17Issue Nr 6 2015 BLAISE PASCAL MAGAZINE

    Next its time to receive the data in Delphi.

    Start RAD Studio, create a VCL Form project,

    and drop a TCLClientSocket from

    CommunicationLab on the form:

    Set the IP Address to the same used in the

    Visuino project 192.168.0.55: Set the Port to 8080:

    ARDUINO: THE VISUINO PROJECT - PART 4 PAGE - 6/15

    INTERNET OF THINGS WITH ARDUINO AND DELPHI

  • 18 Issue Nr 6 2015 BLAISE PASCAL MAGAZINE

    Switch to the OpenWire tab, and connect the

    Output Pin of the Socket to the Input Pin of the

    Terminal:

    Compile and run the application. You will see

    the data arriving in the terminal:

    Drop TCLTerminal on the form:

    ARDUINO: THE VISUINO PROJECT - PART 4 PAGE - 7/15

    INTERNET OF THINGS WITH ARDUINO AND DELPHI

  • 19Issue Nr 6 2015 BLAISE PASCAL MAGAZINE

    If you need to access the data in your code,

    the Socket component has OnReceive event:

    Now you can receive data from Arduino over the

    network, however the data arrives from a single

    sensor, and in text form. This makes it difficult

    to work with, and limits the data channels that

    we can get.

    As shown in the previous article, Visuino and

    CommunicationLab have support for packet

    data. You can use it with sockets the same way

    you did with the serial port.

    Start a new Visuino project, add and configure

    the shield and the socket as you did in the

    previous project.

    ARDUINO: THE VISUINO PROJECT - PART 4 PAGE - 8/15

    INTERNET OF THINGS WITH ARDUINO AND DELPHI

  • Issue Nr 6 2015 BLAISE PASCAL MAGAZINE20

    Connect the Output Pin of the Packet component

    to the Input Pin of the Socket:

    Double click on the packet component to open

    the elements editor. In the editor add 2 Analog

    and 2 Digital elements:

    Next, add a Packet component:

    ARDUINO: THE VISUINO PROJECT - PART 4 PAGE - 9/15

    INTERNET OF THINGS WITH ARDUINO AND DELPHI

  • 21Issue Nr 6 2015 BLAISE PASCAL MAGAZINE

    Connect the Input Pins of the Analog Channels

    to the Output Pins of Analog Input Channel[ 0

    ] and Analog Input Channel[ 1 ], and the

    Input Pins of the Digital Channels to the Output

    Pins of Digital Channel 0 and 1 of the Arduino

    Board component:

    Expand the HeadMarker and for the Bytes click

    on the ... button:

    ARDUINO: THE VISUINO PROJECT - PART 4 PAGE - 10/15

    INTERNET OF THINGS WITH ARDUINO AND DELPHI

  • Issue Nr 6 2015 BLAISE PASCAL MAGAZINE22

    In the Bytes editor enter 55 55, then click OK:

    This will enure that the packet has unique

    header and its starting point can be identified in

    the data stream. Visuino uses special algorithm

    to ensure that the header marker will not appear

    in the packet itself.

    Press F9 to generate, then compile and upload

    the sketch in the Arduino IDE as you did in the

    previous project.

    Now that the Arduino is ready, lets switch to

    Delphi.

    Start a new VCL Form project, add the

    TCLClientSocket, and set the IP Address and Port

    as in the previous project:

    ARDUINO: THE VISUINO PROJECT - PART 4 PAGE - 11/15

    INTERNET OF THINGS WITH ARDUINO AND DELPHI

  • 23Issue Nr 6 2015 BLAISE PASCAL MAGAZINE

    Next add a TCLUnpacket, TSLScope,

    TILAngularGauge and 2 TILLed components:

    Switch to the OpenWire tab, and double click on the

    CLUnpacket1:

    ARDUINO: THE VISUINO PROJECT - PART 4 PAGE - 12/15

    INTERNET OF THINGS WITH ARDUINO AND DELPHI

  • 24

    Add 2 Float and 2 Boolean channels:

    Expand the HeaderMarker and for the bytes click

    on the ... (called ellipsis)

    Issue Nr 6 2015 BLAISE PASCAL MAGAZINE

    ARDUINO: THE VISUINO PROJECT - PART 4 PAGE - 13/15

    INTERNET OF THINGS WITH ARDUINO AND DELPHI

  • 25Issue Nr 6 2015 BLAISE PASCAL MAGAZINE

    In the Bytes editor enter 55 55, then click OK:

    Connect the components as shown in the picture:

    ARDUINO: THE VISUINO PROJECT - PART 4 PAGE - 14/15

    INTERNET OF THINGS WITH ARDUINO AND DELPHI

  • Issue Nr 6 2015 BLAISE PASCAL MAGAZINE26

    Compile and run the application. You will see the

    data arriving from Arduino over the 4 channels:

    When you need to access the data from code,

    you can use the TSLGenericRealValue as

    example to receive the Floating point data and

    process it in the OnProcessData event, as

    shown in one of the previous articles. There are

    also similar components for processing the

    Boolean data included in LogicLab.

    The communication to Arduino is equally easy.

    In order to send the data from Delphi, use

    TCLPacket component and in Visuino use

    Unpacket component.

    BLAISE PASCAL MAGAZINE subscribers that

    visit our PASCON - Event will receive a DVD with

    lots ofprograms, information and as a

    VERY SPECIAL INCENTIVE you will get an

    ARDUINO-BOARD FOR FREE INCLUDING

    THE VISUINO SOFTWARE from Boian Mitov to

    be able to compose and create your own

    software for the board

    CONCLUSION

    This article has given you enough information to

    start communicating with one or more Arduino

    devices over wired network, or Internet from your

    Delphi code. This is your first introduction to the

    exciting world of Internet of Things. In the

    following articles you will learn how to

    communicate with Arduino over WiFi, and how to

    make multiple Arduino boards to talk to each

    other.

    ARDUINO: THE VISUINO PROJECT - PART 4 PAGE - 15/15

    INTERNET OF THINGS WITH ARDUINO AND DELPHI

  • The components found in the Visuino software represent their hardware components and you

    will easily be able to create and design your programs using drag and drop. No equipment or

    hardware is needed to run the software in design mode. Once you have completed the design,

    you can connect Arduino board upload and run it.

    For those people who are not strong on writing code then designing, compiling and creating

    Arduino programs has never been easier! Why waste time on creating code when we have done

    all the hard work for you already? You have your Arduino board, and great hardware design,

    see it running in minutes, not hours!

    Currently we are running a Beta program which you can be part of by joining our Google group.

    Join the group now to download and test the software or send an email to [email protected].

    AVAILABLE ON THE NEXT

    PASCON 15 SEPTEMBER 2015

    What is Visuino?Visuino is the latest innovative software from Mitov Software. A visual programming

    environment allowing you to program your Arduino boards. Although it currently

    supports the official Arduino boards, it is not restricted to their support alone and

    requests to support new hardware are welcome.

    INTRODUCTION What is Arduino?

    VISUINO IS THE LATEST INNOVATIVE PRODUCT

    FROM MITOV SOFTWARE.

    www.visuino.com

  • Issue Nr 6 2015 BLAISE PASCAL MAGAZINE28

    DATABASE WORKBENCH 5 PAGE 1/8 THE SWISS ARMY KNIFE FOR DATABASES BY PETER VAN DER SMAN

    When you start working with databases sooner or

    later you'll come at a point where you start

    searching for a tool to maintain your database.

    After a bit of searching you'll end up using

    FlameRobin when your database is a Firebird

    database, using other databases might result in

    other programs. This is cumbersome at the

    moment you can't avoid using different databases.

    For instance when you have two customers each

    using their own database. Database Workbench is

    database tool working independent from

    databases, that is to say it supports a lot of

    different database managers. Time to take a closer

    look at it.

    EXAMINING A EXISTING DATABASE

    As stated before, Database Workbench does

    support different databases, but is should be said

    the databases you can use is subject to the licence

    you have. Having said that we start using

    Firebird as a starting point as this seems to be the

    database propagated for using with the current

    versions of Delphi. So we start our freshly

    installed program and firstly we have to select

    our previously installed Firebird as Database

    server to use. Then we can start opening a

    existing database. As an example we choose the

    Employees.fdb which comes as a demo with

    your Firebird installation. It gives you directly a

    nice overview ( right column )Figure 1. The content for Employees.fdb

    in the Navigator

    Of course we can use the Navigator as above to

    study the content of all the tables in the database.

    But Database Workbench offers a much more

    handy option for this. After opening a Diagram

    Editor we can use the option Reverse Engineer

    Database to build a schematic overview for the

    database. We can even select to show only a part

    of the Database but, greedy as we are, we of

    course select for the whole database.

    Then we can give the things we like a closer view.

    In the bottom part we find all kinds of

    information about the database itself. A nice one

    are the Connections under Activity. Opening

    this gives a screen showing which programs are

    currently connected to the database. Of course it

    will allways show at least one connection as the

    program itself is connected to it. After making

    another connection, for example in the Delphi

    Data explorer, a second entry will show up (in

    this case bds.exe). Always good to know in case

    you're wondering who is blocking the database.

  • Issue Nr 6 2015 BLAISE PASCAL MAGAZINE 29

    Figure 2. Employees.fdb in the Diagram Editor (part)

    Always difficult to get a nicely looking schema

    for all this linked tables. You should consider it

    as a starting point to make a schema as nice as

    you want to have it. You can replace all tables,

    smarten the links, whatever you like. The

    Navigator is a nice tool to show where you are

    in the total schema. Or to navigate quickly to

    another part. After some manual adjustments

    our schema could be like figure 3.

    DATABASE WORKBENCH 5THE SWISS ARMY KNIFE FOR DATABASES PAGE 2/8

  • Issue Nr 6 2015 BLAISE PASCAL MAGAZINE30

    Figure 3. Employees.fdb in the Diagram Editor

    (after manual adjustment)

    Who would have thought this is all needed for a

    sample employee file! This schema is just of a

    size to overview it at a glance. In the real world

    your schema will easily by a lot larger. Luckily

    enough we have the possibility to make a Sub-

    diagram so you can divide your schema in

    relevant parts.

    In the schema we directly see which fields are

    part of the primary key (having a golden key)

    and which play a role in a reference (having a

    grey key). More information about the table we

    get with a double click on it. For example:

    Figure 4. Columns for table EMPLOYEE

    DATABASE WORKBENCH 5THE SWISS ARMY KNIFE FOR DATABASES PAGE 3/8

  • 31

    More than enough information. You might

    notice the Column Type for EMPNO for the

    column EMP_NO. Looks a bit odd, this has to

    do with defining your own types in Firebird.

    In the schema (figure 1) you can find these

    definitions under Domains. For our database

    has no less than 15 types defined.

    Our EMPNO' turnes out to be of type

    SmallInt. The other tabs in the Table

    Properties form show more information about

    the table. The tab DLL gives you all the code

    needed to create the table.

    This design is used consequently. Double

    clicking in the Navigator (figure 1) on

    different items will result in similar screens to

    popup. No matter if it is about a Domain, a

    View, an Index, a Constraint, a Trigger,

    an Exception or any other item, you'll get Tab

    with relevant detail, and a tab DDL giving

    you the code to implement in the database. In

    fact, you don't really need this code, as we'll see

    later on, but it can be a handy way to check up

    what you have done with an example

    implementation. Unless you're the type

    inventing all by yourself and never looking at

    example code?

    The temptation is strong to directly start making

    all kind of changes. The schema (figure 3) shows

    us an emp_NO, proj_ID en job_CODE. Of

    course there can be puristical reasons the make

    the distinction between NO, ID and

    CODE, but perhaps you would prefer to

    change this all to ID. The good news is we

    actually can easily make these changes in the

    screen as shown in figure 4. Just change

    EMP_NO to EMP_ID. The bad news is it

    won't be of any use.

    The diagram in the diagram editor is not

    connected to a physical database.

    The consequence is we cannot pass our changes

    made to the database. In fact this is a good thing.

    In a designing phase it could be a nice idea to

    make the proposed changes, making them in an

    existing database can be quite disastrous.

    There's every change that these fields play a part

    in a trigger, a view or a procedure. In fact, we

    can change fieldnames using Database

    Workbench: just open a table from the navigator

    and change the name of the field. In this screen

    there is this handy button Create/Alter Table.

    Nine times out of 10 this will result in a message,

    from Firebird, telling you the update was

    unsuccessful due to data integrity.

    But changing the AGED field from the table

    SALES will work fine using this option.

    The other way around will work fine. The option

    Update From Database can be used to match

    your diagram with an existing database. The

    lay-out we made with so much effort (figure 3)

    will be maintained.

    DESIGNING A NEW DATABASE

    The previous part showed Database Workbench

    5 can be used to analyse the structure of a

    database we received from a third party. But is it

    of any good designing a new database? You

    understand this question is rhetorical. Of course

    we can. Let's just do it!

    CONCEPTUAL AND PHYSICAL DIAGRAMS

    The best way to start a new design is designing

    it using the Diagram Editor. Starting with an

    empty Diagram we'll find under the New

    button two options: New Conceptual

    Diagram and New Physical Diagram. It is

    just like is sounds: you can start making a more

    sketchy diagram or directly start with a design

    tailored to the possibilities your database

    manager of choice provides. If this would not be

    clear at first sight: after selecting a New

    Physical Diagram you must point out for which

    database you're going to design.

    Figure 5. The first conceptual

    diagram

    So we choose for a

    Conceptual

    Diagram and get an

    empty working area

    where we can drop

    new tables. Of

    course I could have

    chosen to redesign

    this inevitable

    databases like

    Employees or

    FishFacts, but let's

    design a brandnew

    database we can use

    to browse all articles

    ever published in

    Blaise. Our first go

    would be to have

    three tables: blaise

    edition, writer

    and article. So we

    drop three tables (in

    this phase named

    Entities) on our working area, double click on

    them to give them meaningful names and

    adding some fields (in this phase named

    Attributes). After some rearrangement it could

    look like this

    DATABASE WORKBENCH 5THE SWISS ARMY KNIFE FOR DATABASES PAGE 4/8

    Issue Nr 6 2015 BLAISE PASCAL MAGAZINE

  • Issue Nr 6 2015 BLAISE PASCAL MAGAZINE32

    Note I did'nt mind about the type definition

    for my fields. No reason to bother about it

    right now, we can just focus in getting the

    general structure right.

    Looking to our design we note the field

    Language appearing in two tables. So

    most likely we should consider adding a

    new table/entity Languages. And of

    course we must find a way to bind the

    Articles to the proper Blaise edition.

    The most flexible way to do it is using a new

    table making the connecting between the

    two tables. It gives the editor a way to

    republish an article . Speaking about this:

    most articles in effect will be republished in

    different editions, that is to say, in

    translation. So apart from the writer of the

    original version there can be a translator

    too. And we should be able to refer to the

    original article. So we can add a table

    Translators, but the easy way is to use the

    table Writers for this purpose as well. This

    directly solves the problem of persons who

    both write articles and translate articles as

    well. And besides, writing an article or

    translating, both are a kind of writing. And,

    in case you had noticed, we now have a

    reason to use author in the Articles table

    Figure 6. The half worked out conceptual diagram

    In the real world this would be the moment to

    put it aside and to look at it again at a later point

    of time and discussing it with a colleague.

    However, in the world of Blaise the next edition

    is coming soon, so we continue with our schema

    right away. We do a bluff and ask Database

    Workbench to convert this schema to a

    Physical Diagram for Firebird. The result is a

    pile of error messages: this is the time we should

    point out the datatypes we are going to use.

    Further on we did make connections between

    tables, but I didn't really bother working them

    out. The good news is we don't have to search

    ourselves for missing data, we just get a list of

    items to resolve. We can't blame the program it

    initially is a long list. The following schema

    shows the more adapted conceptual schema

    (figure 7).

    referring to a table writers. And a fieldname

    date is a bit ambiguous, so let's change it to

    DatePublished right away.

    Let's make some connections as well. The icons

    as shown in figure 5 point out we can use three

    kinds of links: Identifying Relationship,

    Non-Identifying Relationship and Documentation

    link. The last one is meant to make connections

    just for clarifications in the diagram, not for

    implementing in the database. After some not

    too hard labour it could look like this.

    Figure 7. The fully adapted conceptual diagram

    DATABASE WORKBENCH 5THE SWISS ARMY KNIFE FOR DATABASES PAGE 5/8

  • 33Issue Nr 6 2015 BLAISE PASCAL MAGAZINE

    Where needed I provided for a unique key field

    in all tables. All fields are given a type. Just for

    showing the differences I used some different

    types. And the connections are filled in with

    relevant information. To get a nice picture I

    removed the connection between

    OriginalVersion and ArticleID from the

    Diagram. But it still exists. To show it a Sub-

    diagram can be used:

    Figure 7b. The Articles sub-diagram

    FROM CONCEPTUAL TO PHYSICAL DIAGRAM

    So now we are ready to convert to a physical

    schema. This is the point to decide on which

    database manager our database must be build. The

    next thing to select the option Generate Physical

    Diagram and select for Firebird resulting to the

    following screen.

    Figure 8. Conversion to Firebird

    We just take the standard options, including

    Firebird 3.0, and then click OK. That's all to get a

    diagram adjusted for the desired database. All

    types are translated to types provided by our

    database. To illustrate this I made two

    conversions, one to Firebird and one to MySQL.

    The differences for the table Articles are

    shown in figure 9. In fact you'll see just one

    difference, the conversion of the type Unicode

    text in the Abstract field . For Firebird it is

    converted to BLOB(text), for MySQL the

    LongText is used.

    Figure 9a. Table Articles for Firebird.

    Figure 9b. Table Articles for MySQL

    After looking closely to the final schema

    again, it will probably result in some

    desired changes. We don't have to go back

    to the conceptual diagram, we just can

    make the changes in our conceptual

    diagram. The interface is nearly the same.

    So - if this is the moment - we realise the

    Dutch Edition 126 is a translated version

    of the English 44 edition and we should

    provide a way bring this into the database

    we can adjust the table Blaise (in the

    same way we did for Articles):

    Figure 10. Adapted Table Blaise

    DATABASE WORKBENCH 5THE SWISS ARMY KNIFE FOR DATABASES PAGE 6/8

  • 34

    The reference from OriginalVersion back to the

    table Blaise is called a Constraint. It is build

    using the following screen.

    Figure 11a. Definition of a Constraint

    And, as promised before, if we really would be

    interested we could find the code needed to add

    this Constraint to the database in the DDL tab:

    Issue Nr 6 2015 BLAISE PASCAL MAGAZINE

    DATABASE WORKBENCH 5THE SWISS ARMY KNIFE FOR DATABASES PAGE 7/8

  • 35Issue Nr 6 2015 BLAISE PASCAL MAGAZINE

    Of course now we have to doubel check the total

    schema again and adapt it where necessary.

    We could add a Check Constraint, an Index or a

    Trigger where desired.

    After doing this we can use the schema to build a

    real database. We have two options available.

    The hard way is to use the option Extract DDL For

    ALL Objects. It provides us a SQL script to be

    used for generating the database. The advantage

    might be you can recheck the script before

    running it and/or maybe add some very special

    code you couldn't add using the program.

    And the script can be useful for documentation

    purposes. But we also can use the easy way.

    Just take the option Create Database from

    Diagram and follow the instructions in the

    Wizard. It will ask you the location of the

    database, username and password and so on.

    When we're done the database will be created

    and the script will run in order to create your

    structured tables. In anything does go wrong

    with the script it will pop-up in the script editor

    so you can make your adjustments. .

    DATABASE WORKBENCH 5THE SWISS ARMY KNIFE FOR DATABASES PAGE 8/8

    EPILOGUE

    Database Workbench is a handy tool for

    working with databases. Either in case you want

    to examine an unknown database delivered to

    you or in case you want to design a brand new

    database, in both cases the program offers you a

    lot of support to do so. Of course you can find

    loads of other programs doing this. The nice

    thing about Database Workbench is it supports

    multiple databases. So in case you're working

    with different databases you only have to know

    about one single tool instead of learning about a

    tool for each different database

  • 36 Issue Nr 6 2015 BLAISE PASCAL MAGAZINE

    better office benelux | asterlaan 6 5582EH waalre | 040 222 26 43 [email protected]

    Benno Evers is our specialist for questions about

    kbmMW.

    He can help you with basic questions regarding kbmMW

    as well as with turnkey Development and Consultancy.

    Hes a specialist in netwoks, internet and hardware.

    Specialist help and consultancy

    for kbmMW

    [email protected]

    CUSTOM TECHNOLOGY

    COMPONENTS

    DEVELOPERS4

  • http://www.blaisepascal.eu/DucthPascon/Pascon2015UK.html

  • 1 2 34

    5126

    7 8

    1314 15

    16 17

    25 262720

    2128 22 23

    24

    3334 35

    36

    37 38

    39

    40 41

    42

    3229 30 31

    910

    1118 19

    WINDOWS 10

    L I B R A R Y 2 0 1 5

    B L A I S E P A S C A L M A G A Z I N E

    A L L I S S U E S I N O N E F I L EA U T H O R S A L FA B E T I C A L

    CLICK TO OPEN

    ITEM (NUMBER)

    CLICK TO OPEN

    ITEM (NUMBER)

    CLICK TO OPEN

    DELPHI URL

    CLICK TO OPEN

    A BROWSER WITH

    URL

    CLICK TO OPEN

    THE TOTAL

    OVERVIEW OF ALL

    ITEMS IN ONE

    CLICK TO OPEN

    THE TOTAL

    OVERVIEW OF ALL

    ITEMS IN ONE

    www.blaisepascal.eu/subscribers/UK/UK_CD_DVD_USB_Department.html

    Issue Nr 6 2015 BLAISE PASCAL MAGAZINE 38

  • Delphi

    expertstarter

    Issue Nr 6 2015 BLAISE PASCAL MAGAZINECOMPONENTS

    DEVELOPERS439

    TIPS AND TRICKS WITH KBMMEMTABLE PAGE 1/9

    kbmMemTable is an in memory row/column

    oriented database which have a vast

    number of features and which is very fast in

    both storing data and locating stored data.

    I will in this article focus on some basic

    things and on some of the less known,

    but very useful, features of kbmMemTable.

    var

    : ;mt TkbmMemTable

    begin

    // Define fields (you may already

    // have them defined at designtime).

    . . ( , );mt FieldDefs Add ftInteger'ID'

    . . ( , , );mt FieldDefs Add ftString'Name' 80

    . . ( , , );mt FieldDefs Add ftString'Address' 80

    // Define indexes (if you have a large amount of records

    in your mt

    // indexes will make searches faster, but inserts/edits slower).

    . . ( , ,[ ]);mt IndexDefs Add ixPrimary'iID' 'ID'

    . . ( ,mt IndexDefs Add 'iName'

    Name',[ ]);ixCaseInsensitive

    . ;mt CreateTable

    . ;mt Open

    end;

    When searching on for records using the Name

    field as search criteria, we have defined that it

    should search case insensitively, so for example

    uppercase A is the same as lowercase a.

    FAST INSERTION INTO THE DATABASE

    kbmMemTable exists in two primary versions,

    Standard Edition and Professional Edition.

    Standard Edition can be purchased separately,

    while Professional Edition only is available as a

    bundle with kbmMW Professional or kbmMW

    Enterprise Edition.

    While kbmMemTable Professional is the

    absolutely fastest memory table in the world,

    kbmMemTable Standard Edition can almost reach

    its performance when used correctly.

    If you are to insert a large number of records in

    kbmMemTable Standard Edition, then you will

    want to do like this:

    var

    ,fldID

    ,fldName

    : ;fldAddress TField

    begin

    // First get quick access to the fields.

    // This prevents having to search for a field each

    // and every time a record is to be inserted.

    := . (' ');fldID mt FieldByName ID

    := . (' ');fldName mt FieldByName Name

    := . (' ');fldAddress mt FieldByName Address

    // Prevent update of attached controls on each insert.

    // This is a big performance factor when inserting huge

    // amounts of records.

    . ;mt DisableControls

    // Prevent update of indexes on each insert. Professional

    // Edition is much faster in on the fly updates of indexes,

    // so it will perform extremely fast even without disabling

    // indexes while inserting. But the highest performance

    // is obtained by disabling them before the batch insert.

    . := ;mt EnableIndexes false

    // Insert a lot of records.

    := for to doi 1 1000000

    begin

    . ;mt Append

    . := ;fldID AsInteger i

    . :=' '+ ( );fldName AsString Name inttostr i

    . :=' '+ ( );fldAddress AsString Address inttostr i

    . ;mt Post

    ;end

    // Enable and update indexes.

    . := ;mt EnableIndexes true

    . ;mt UpdateIndexes

    // Enable updating attached controls (grids etc).

    . ;Mt EnableControls

    HOW TO SEARCH?

    You either choose to switch to the index

    representing the column(s) you want to search

    on, or you simply just search and let

    kbmMemTable find a relevant index (if any) to

    use for the search.

    If you want the absolutely fastest result, then you

    should switch to the index first, to avoid that

    kbmMemTable have to make an additional

    search on your current index to sync with the

    found place in the search index.

    However the second index sync search is

    generally very fast.

    You can use Locate to search for a complete name

    for example. If it finds a record with the given

    name, that record will be the current record, and

    you can access other fields in it immediately.

    if then . ( , ,[]) mt Locate 'Name' 'Jens Hansen'

    (MessageDlg 'Found record.

    Address=' 'Address'+ . ( ). );mt FieldByName AsString

    CREATE A MEMORY TABLE WITH

    INDEXES IN CODE

    The Codegear edition is for free and can do it all

    But it only supports specific versions... eg only

    new xe8 has supprt for latest kbmmemtable.

    Xe7 supports older kbmmt and edition xe2 even

    older etc.

    BY KIM MADSEN

  • PAGE - 2/4

    Issue Nr 6 2015 BLAISE PASCAL MAGAZINE COMPONENTS

    DEVELOPERS440

    You can use Lookup to search for a record

    containing the given value, and return the

    contents of any field as result. It will not move

    the current record.

    v mt Lookup:= . ( , , );'Name' 'Jens Hansen' 'Address'

    ( ) if not thenVarIsNull v

    ( + );MessageDlg v'Found record.Address='

    You can also search for partial values

    if . ( , ,[ ]) mt Locate loPartialKey'Name' 'Jens'

    then MessageDlg mt FieldByName AsString( + . ( ). );'Found record. Address=' 'Address'

    How to search on multiple fields?

    Let kMemTable automatically create indexes for you

    to improve search performance

    This may however result in creation of many indexes

    over time if you often search on new columns and

    having many indexes to maintain when

    inserting/editing/deleting records will always give a

    performance penalty, so use with care.

    HOW TO SORT?

    Adding an index will always result in the data

    being sorted according to an index. So you can

    add an index and switch to it.

    Or even easier:

    HOW TO ONLY SHOW CERTAIN RECORDS?

    For this purpose, you can use a range or a filter.

    A range can limit the records displayed in for

    example a grid, to show only records within a

    range (eg. 10 Greater than

    < Less than

    >= Greather than or equal

  • Issue Nr 6 2015 BLAISE PASCAL MAGAZINECOMPONENTS

    DEVELOPERS441

    This creates a new index, ordered (and quickly

    searchable) by ID, and filtered by the given

    filter string. You can filter on any field or

    calculation of fields. It doesn't have to be fields

    that are in the key fields list.

    Every time you add or alters records, the index

    will be updated and records may this way

    disappear or appear in the filtered index

    depending on the values of the record.

    When you switch to a filtered index, and thus

    only show the records participating in that

    index, scrolling through or searching isjust as

    fast as if you had no filter defined. Inserts and

    updates have a small performance penalty, so

    if you have many records to insert, use the

    batch insert method outlined earlier in this

    article.

    STANDARD INDEXES?

    With standard indexes, I refer to indexes

    which are created/defined by the memtable

    during its course of operation.

    When a memory table is opened, there always

    exist one single index, the row order index. It's

    the index that is updated to ensure that order

    of insertion of records can be established.

    It's also responsible for holding a reference

    to all records. The row order index is selected

    by setting the IndexName to an empty string.

    Internally you will find the roworder index to

    be named '__MT__ROWORDER_'. A string constant

    exists for that name: kbmRowOrderIndex.

    The row order index can't be deleted.

    Further a number of other indexes may be

    defined at various occations.

    Functions:

    UPPER( expression )

    Convert string expression to uppercase.

    LOWER( expression )

    Convert string expression to lowercase.

    SUBSTRING( expression , startpos , count )

    Extract a substring from the expression string

    starting at startpos and with max length of count

    chars. The count parameter can be omitted, in

    which case is means the rest of the string.

    TRIM( expression ) Trim string expression for all

    leading and trailing spaces.

    TRIMLEFT( expression ) Trim string expression

    for all leading spaces.

    TRIMRIGHT( expression ) Trim string expression

    for all trailing spaces.

    GETDATE Returns a floating point date/time

    value for current time.

    YEAR( expression ) Return the year of a floating

    point date/time value.

    MONTH( expression ) Return the month of the year

    (1..12) of a floating point date/time value.

    DAY( expression ) Return the day of the month

    (1..28/29/30/31) of a floating point date/time

    value.

    HOUR( expression ) Return the hour (0..23) of a

    floating point date/time value.

    MINUTE( expression ) Return the minute (0..59) of

    a floating point date/time value.

    SECOND( expression ) Return the second (0..59) of

    a floating point date/time value.

    DATE( datestring , formatstring )

    Convert the datestring to a floating point

    date/time value according to the

    SysUtils.FormatDateTime format string .

    DATE( expression ) Return the date part of a

    floating point date/time value.

    TIME( timestring , formatstring )

    Convert the timestring to a floating point

    date/time value according to the

    SysUtils.FormatDateTimeformat string .

    TIME( expression ) Return the time part of a

    floating point date/time value.

    Filtering however is done on each record every

    time that record is accessed, thru scrolling or

    counting number of records etc. So it's fairly slow

    on large datasets to use a filter.

    A better way, is to create a filtered index. That is a

    real index which only contains references to records

    that live up to the filter expression.

    mt AddFilteredIndex. ( , ,[], ,[]);'iFilteredIndex' 'ID' '(ID>=10) AND (ID

  • Issue Nr 6 2015 BLAISE PASCAL MAGAZINE COMPONENTS

    DEVELOPERS442

    kbmMemTable supports whats called

    transaction management via the methods

    StartTransaction, Commit and Rollback.

    Further it also supports an Undo function on

    the record level. More about that in a moment.

    To use transaction management, one also need

    to understand versioning.

    kbmMemTable have two properties controlling

    versioning: EnableVersioning and

    VersioningMode. EnableVersioning is a

    Boolean, while VersioningMode can have

    the value of mtvm1SinceCheckPoint or

    mtvmAllSinceCheckPoint.

    Versioning allows kbmMemTable to store

    multiple versions of the same record.

    Whenever a record is inserted into the

    memory table, one version of that record

    exists, the one that was inserted.

    Default EnableVersioning is false and thus

    the records you see in the memory table are

    the ones you have.

    No other versions are created.

    If EnableVersioning is set to true, then

    kbmMemTable will start to make multiple

    versions of a record, depending on the setting

    of VersioningMode.

    If VersioningMode is set to

    mtvm1SinceCheckPoint, then at most, an

    original version is kept, and the altered one.

    This is cool, if you need to update an external

    storage with the changes made in the memory

    table.

    Then the original version identifies what you

    have to search for, and the new version

    identifies what to change to.

    A deltahandler is what is used for handling

    those scenarios, but now we will focus on

    transactions. So in this case, you can only

    undo back to the original version, and not

    intermediate changes.

    INDEX INHERITANCE

    If you want to temporarily sort on a different

    field than the ones participating on the current

    selected index (it could for example be a filtered

    index), you simply do SortOn, as described

    earlier on, while having the filtered index

    selected.

    This will create a new sorted index, based on

    the filtered index, so only records that are

    acceptable in the base index, are candidate for

    inclusion in the new sort index.

    TRANSACTIONS AND VERSIONING

    If you make modifications to a number of

    records in a table, it would, in some situations,

    be nice to be able to roll back those changes in

    one go. For example if you have an application

    where the user can make modifications to a

    number of entries (inventory for example), and at

    a later stage decide to save those changes or

    cancel them. Cancelling the changes would

    require a roll back, while saving means that the

    user commits to his changes.

    '__MT__DETAIL_' (kbmDetailIndex).

    This index is created (and automatically recreated)

    when the master record changes in a master/detail

    relationship. It ensures that browsing through

    detail records is very fast, and quick to search on.

    '__MT__DEFSORT_' (kbmDefSortIndex).

    This index is created when you are using the Sort

    or SortOn methods. It is only recreated when you

    issue another Sort/SortOn method call.

    '__MT__DEFAULT_' (kbmDefaultIndex).

    This index is automatically created when you set

    IndexFieldNames to a set of fields for which no

    index already exist.

    '__MT__RANGE_' (kbmRangeIndex).

    This index is automatically created when you

    apply a range filter.

    '__MT__AUTO_' (kbmAutoIndex). This is

    actually not only one index, but potentially many

    indexes, which are automatically created if you

    have the property AutoAddIndexes set to true,

    and you make a search locate/lookup)

    on fields for which there are no existing indexes

    available. The actual indexname will be

    '__MT__AUTO_' + the semicolon separated field

    names. Be aware that this index is not

    automatically destroyed, so if you search on many

    weird combinations of fields, you may end up

    with many indexes, and may need to delete them

    yourself if needed.

    TIPS AND TRICKS WITH KBMMEMTABLE PAGE 4/9

  • If you compile and upload the Arduino code as described in the

    previous articles, and then connect to it with Visuino, you will see the

    sine wave deformed by the quadratic function plotted in the scope:

    Issue Nr 6 2015 BLAISE PASCAL MAGAZINE43

    THE DELTAHANDLER

    A deltahandler is a class that can scan through

    a memory table, and determine what has

    happened with each record, and allow the

    developer to do something depending on what

    happened.

    Was it inserted, deleted, modified or was

    nothing changed with it?

    It is essentially a great tool for making changes

    in your dataset resolve back to from where the

    data originated from (typically a SQL database or

    files in a file system etc).

    This is a simple deltahandler:

    Example:

    In this example a record is inserted, a transaction is

    started, then the record is edited and then deleted.

    With VersioningMode set to

    mtvm1SinceCheckPoint, then you can only

    choose to roll back to where the record was

    inserted. The version containing the edited record is

    lost the moment the record is deleted. Only one

    version in addition to the original record is kept.

    To allow for a multi level undo, then

    VersioningMode should be set to

    mtvmAllSinceCheckPoint. Then you can do

    this:

    You see you can nest transactions this way.

    If you want to make a change, that is protected by a

    StartTransaction, stick, then you call

    mt.Commit. After the commit, the change can only

    be rolled back if there are multiple levels of nested

    transactions as in this example:

    You can check the state of a record by checking the

    UpdateStatus property. It returns the current

    records state. Was it inserted (usInserted),

    deleted (usDeleted), modified (usModified)

    and unchanged (usUnmodified). To actually see

    usDeleted marked records, it require adding and

    switching to a special index that allows for showing

    deleted records check the overloaded version of

    AddIndex which accepts providing a set of

    UpdateStatus flags, for which records to include

    in the index.

    When you insert/append records, those will be

    marked with usInserted as their

    UpdateStatus propery. That also happens when

    you load the records from another dataset, because

    technically they have been inserted into the

    memory table. You can however ask kbmMemTable

    to consider these newly loaded records, as being

    the original ones and thus that they should have

    the UpdateStatus of usUnmodified.

    The latest version of any record is now considered

    the original version and marked as

    usUnmodified, and all intermediate versions

    have been removed. That also means that if records

    were deleted, they are now permanently deleted

    and can't be recovered. To undo last change of the

    current record, you can use:

    Remember that the number of undo's you can

    make on the current record, depends on the

    setting of EnableVersioning and

    VersioningMode.

    // An example on how to create a deltahandler.

    TMyDeltaHandler TkbmCustomDeltaHandler = ( )class

    protected

    ( : ; procedure varInsertRecord Retry boolean

    var override : ); ;State TUpdateStatus

    ( : ; procedure varDeleteRecord Retry boolean

    var override : ); ;State TUpdateStatus

    ( : ;procedure varModifyRecord Retry boolean

    : ); ;var overrideState TUpdateStatus

    // procedure UnmodifiedRecord(var Retry:boolean;

    var State:TUpdateStatus); override;

    end;

    mt AppendRecord. ();

    mt StartTransaction. ;

    mt Edit mt Post. . . ;

    mt Delete. ;

    mt Rollback. ;

    mt AppendRecord. ();

    mt StartTransaction. ; // First level of transaction

    mt Edit mt Post. . . ;

    mt StartTransaction. ; // Second level of transaction

    mt Delete. ;

    mt Rollback. ; // Back to the edited record again

    mt Rollback. ; // Back to the original appended record

    mt AppendRecord. ();

    mt StartTransaction. ; // First level of transaction

    mt Edit mt Post. . . ;

    mt StartTransaction. ; // Second level of transaction

    mt Delete. ;

    mt Commit. ; // We will keep the delete but not the

    edited record.

    mt Rollback. ; // Ah no.. we will revert to the original

    appended record

    mt CheckPoint. ;

    mt Undo. ;

    TIPS AND TRICKS WITH KBMMEMTABLE PAGE 5/9

    COMPONENTS

    DEVELOPERS4

  • procedure var var . ( : ; : );TMyDeltaHandler InsertRecord Retry boolean State TUpdateStatus

    var string : ; , : ; : ;i integer s sv v variant

    begin

    := ;s ''

    := - for to doi FieldCount0 1

    begin

    := [ ];v Values i

    ( ( )) :=if then VarIsNull v sv ''

    ( [ ]. ) :=else if not in then Fields i DataType kbmBinaryTypes sv v

    else

    := ;sv ''

    := + + ;s s sv ' '

    ;end

    ( ( ,[ ]));ShowMessage Format s'Inserted record (%s)'

    end;

    procedure var var . ( : ; : );TMyDeltaHandler DeleteRecord Retry boolean State TUpdateStatus

    var string : ; , : ; : ;i integer s sv v variant

    begin

    := ;s ''

    := - for to doi FieldCount0 1

    begin

    := [ ];v Values i

    ( ( )) :=if then VarIsNull v sv ''

    ( [ ]. ) :=else if not in then Fields i DataType kbmBinaryTypes sv v

    := ;else sv ''

    := + + ;s s sv ' '

    ;end

    ( ( ,[ ]));ShowMessage Format s'Deleted record (%s)'

    end;

    procedure var var . ( : ; : );TMyDeltaHandler ModifyRecord Retry boolean State TUpdateStatus

    var stringi integer s1 s2 sv v variant: ; , , : ; : ;

    begin

    := ;s1 ''

    := ;s2 ''

    := - for to doi FieldCount0 1

    begin

    := [ ];v Values i

    ( ( )) :=if then VarIsNull v sv ''

    ( [ ]. ) :=else if not in then Fields i DataType kbmBinaryTypes sv v

    := ;else sv ''

    := + + ;s1 s1 sv ' '

    := [ ];v OrigValues i

    ( ( )) :=if then VarIsNull v sv ''

    ( [ ]. ) :=else if not in then Fields i DataType kbmBinaryTypes sv v

    := ;else sv ''

    := + + ;s2 s2 sv ' '

    ;end

    ( ( ,[ , ]));ShowMessage Format s2 s1'Modified record (%s) to (%s)'

    end;

    //procedure TMyDeltaHandler.UnmodifiedRecord(var Retry:boolean; var State:TUpdateStatus);

    //begin

    //end;

    And :you start the deltahandler like this

    var

    : ;myDeltaHandler TMyDeltaHandler

    begin

    := . ( );myDeltaHandler TMyDeltaHandler Create nil

    try

    . := ;mt DeltaHandler myDeltaHandler

    . ;mt Resolve

    finally

    . := ;mt DeltaHandler nil

    . ;myDeltaHandler Free

    ;end

    end;

    TIPS AND TRICKS WITH KBMMEMTABLE PAGE 6/9

    Issue Nr 6 2015 BLAISE PASCAL MAGAZINE COMPONENTS

    DEVELOPERS444

  • LOADING DATA

    Data can be loaded into a memory table in multiple

    ways:

    1. Inserting them one record at a time

    2. Loading the data from another dataset

    3. Loading the data from a file

    As for 1, you can use the ordinary Insert/Post, or

    AppendRecord methods.

    As for 2, you can use:

    mt.LoadFromDataset(anotherdataset,

    [mtcpoStructure]);

    This will make your memory table have the same

    fields as the anotherdataset (due to the

    mtcpoStructure option), and load a copy of all data

    from the dataset into the memory table.

    A number of copy options exists:

    mtcpoStructure:

    Copies table structure (field definitions) from the

    source. Any field definitions you had in your local

    memory table are removed.

    mtcpoOnlyActiveFields:

    Only field definitions in the source that actually

    are represented as a true field, are copied.

    mtcpoProperties:

    Copy over field properties like DisplayWidth,

    DisplayLabel, Required, ReadOnly,

    Visible, DefaultExpression,

    Alignment, ProviderFlags, Lookup,

    LookupCache, LookupDataset,

    LookupKeyFields, LookupResultField,

    KeyFields, DisplayFormat,

    EditFormat, MaxValue, MinValue,

    DisplayValues, TransLiterate,

    Precision, Currency and BlobType.

    mtcpoLookup:

    Also copy lookup fields from the source dataset.

    mtcpoCalculated:

    Also copy calculated fields from the source

    dataset.

    mtcpoAppend:

    Append records to the existing records in the

    memory table. This cant be used with

    mtcpoStructure or mtcpoProperties.

    mtcpoFieldIndex: Copy the index position of

    fields to ensure field order is the same as in the

    original.

    mtcpoDontDisableIndexes:

    Default a batch insertion is made, where indexes

    are only updated after all records have been

    copied over. However if you for example have an

    index with unique constraint on a field, then you

    might want to have your copy to stop early, if

    there is a duplicate of that field value.

    That require that the indexes are updated on the

    fly for each record. Standard Edition will have a

    larger performance penalty than Professional

    Edition of kbmMemTable for this situation.

    mtcpoIgnoreErrors:

    Ignore any copy errors instead of stopping

    copying.

    mtcpoLookupAsData:

    Copy over lookup fields a regular datafield, with

    its matching data.

    mtcpoCalculatedAsData:

    Copy over calculated fields as a regular data field

    with its calculated data.

    mtcpoStringAsWideString:

    Assume that source ftString, ftFixedChar fields

    should be created as ftWideString in your local

    memory table.

    mtcpoWideStringUTF8:

    If string/character/memo fields in the source

    dataset do not match wideness of the same in

    the destination dataset (your local memory table),

    then automatically encode or decode to/from

    UTF8. Eg.

    If the source dataset has field 'str1' which is a

    ftWideString field, while the local

    memorytable has the same field 'str1' defined as a

    ftString field, it will UTF8 encode the data

    coming from the source field before putting it into

    the destination field. Similarly if a source field is

    of type ftString, but the destination is of type

    ftWideString then an UTF8 decoding will take

    place before putting the value into the destination

    field. The same takes place with

    ftMemo/ftWideMemo and

    ftFixedChar/ftWideFixedChar.

    If you already have an existing field structure in

    your local memory table, and want to copy fields

    from a source dataset, where the field names do

    not match, you can take advantage of field name

    mapping.

    Eg.

    This is telling kbmMemTable that the local field

    named str1 is called str_1 in the source table etc.

    As for option 3, loading from a file, you can use:

    mt.LoadFromFileViaFormat('somefilename',

    someformatinstance);

    mt LoadFromDataset anotherdataset. ( ,

    [], );'str1=str_1;int2=int_2'

    TIPS AND TRICKS WITH KBMMEMTABLE PAGE 7/9

    Issue Nr 6 2015 BLAISE PASCAL MAGAZINE45COMPONENTS

    DEVELOPERS4

  • Its practical if the data of field fld1 is required to

    be quickly accessible in your string list. In this

    example, s will only contain the value of fld2. If

    you need the field value both as an object and as

    part of the string, you can include it twice in your

    field list.

    Eg. 'fld1;fld1;fld2'.

    A different extraction method is GetRows which

    returns requested fields as an array of an array of

    variant.

    This will return an array of variant containing an

    array of variant of size 1, with the contents of the

    field with FieldNo=1.

    Eg. v[0,0] is the value of the first field of the first

    record.

    Since we specified to ask for kbmGetRowsRest

    number of records, starting with

    kbmBookMarkFirst, then we are essentially

    asking for all records. If we wanted to start from

    another place in the record set, you should

    provide a TBookmark value for that place.

    That is created by navigating to the record, then

    use the Bookmark function to obtain a bookmark

    for exactly that place in the record set.

    And by providing a number instead of

    kbmGetRowsRest, you can limit the number of

    records returned to that particular count.

    The last argument of GetRows, can either be a

    field number, a field name or an array of field

    numbers or an array of field names.

    someformatinstance is an instance of a stream

    format component. kbmMemTable comes with

    two, TkbmMemBinaryStreamFormat and

    TkbmMemCSVStreamFormat.

    The binary stream format class stores data

    compactly and efficiently, and is giving the

    fastest performance. However the CSV stream

    format class allows you to read in (and write out)

    comma separated formatted data, for easy

    integration with other external systems.

    kbmMW (our middleware product) comes with

    additional stream formatters for XML and JSON.

    Each stream format instance have a number of

    flags that can be set, to tell how it's supposed to

    handle the reading or writing of data, but that is

    a story for another time.

    sf TkbmMemCSVStreamFormat Create:= . ( );nil

    try

    . ( , )mt LoadFromFileViaFormat sf'.\mydata.csv'

    finally

    . ;sf Free

    end;

    EXTRACTING DATA

    A number of methods exist for easily extract data

    from a memory table.

    mt.Extract('fld1;fld2',slData);

    This one will extract the fields fld1 and fld2 for all

    records to a TStrings instance (TStringList

    typically) that you will have to create beforehand.

    If the optional AFormat string is given, each line

    in TStrings will be formatted according to that

    format. If none is given, then all field values for a

    record will be separated by a space.

    The above example will thus put a space between

    the value of fld1 and fld2 for each record/line.

    mt.Extract('fld1;fld2',slData,'%s=%s');

    This will put an equal

    sign between the value

    of fld1 and fld2.

    It is also possible to specify that the first field (in

    the following case fld1) should be stored as an

    object for the text line in the strings list.

    mt.Extract('fld1;fld2',slData,'',true);

    Then you can access that value by:var v variant: ;

    begin

    := ( . [ ] v TkbmVariantObject slData Objects i

    ). ;Value

    := . [ ];s slData Strings i

    end;

    var v variant: ;

    begin

    := . ( , , );v mt GetRows kbmGetRowsRest kbmBookMarkFirst 1

    end;

    v mt GetRows kbmGetRowsRest kbmBookMarkFirst VarArrayOf:= . ( , , ( , ));'fld1' 'fld2'

    TIPS AND TRICKS WITH KBMMEMTABLE PAGE 8/9

    Issue Nr 6 2015 BLAISE PASCAL MAGAZINE COMPONENTS

    DEVELOPERS446

  • STATISTICS

    kbmMemTable contains a number of

    functions to allow very fast grouping and

    calculation of statistical values for your

    data. Returning a sum of fld1 for all records

    visible in the current index.

    v will contain the sum of fld1 for all records in the

    current index.

    v[0] will contain the sum of fld1 for all records in

    the current index. v[1] will contain the standard

    deviation for the records, and v[2] will contain the

    count of records. The following functions can be

    used:

    MAX, MIN, AVG, COUNT, SUM, STDDEV

    and USR1,USR2,USR3.

    The USRx f