Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Joint Database Technology

by erichansen1836 (Acolyte)
on Mar 24, 2015 at 21:40 UTC ( #1121222=perlquestion: print w/replies, xml ) Need Help??
erichansen1836 has asked for the wisdom of the Perl Monks concerning the following question:

Is anyone else besides me using? what I call JOINT DATABASE TECHNOLOGY, i.e. tandem/dual use of: Flat "text" File databases (w/fixed-length records) for massive data storage, along with binary Perl SDBM databases of key/value pairs (tied to "in memory" program hash tables) for persistent random access indexing into the Flat File records. I believe this falls under the categories of both: Relational, ISAM (Indexed Sequential Access Method), and NoSQL, and Embedded Database. Parent/Child one-to-many record relationships are supported as well as Lookups to eliminate redundant data in the Flat Files.

Suited best for: Data Warehouses, Data Marts, Decision Support Systems (DSS), & Executive Information Systems (EIS) or Executive Support Systems (ESS).

The KEY in the SDBM KEY/VALUE pair is one or more fields and/or partial fields contained within the fixed-length records of a Flat File.The VALUE is the record offset (in bytes) to set the file pointer in a Flat File before performing READ/WRITE operations. Supported are Unique Primary Key, Unique Alternate Keys, and Alternate Keys with Duplicates.

I use fixed-length record flat file databases to store large amounts of data with large record lengths. In tandem with this, I use Perl SDBM database files to store the integer(pos+/neg-) record offsets (in bytes) used to seek to flat file records by the file pointer, from either the top or end of file. If the integer used is a negative number, the byte position is relative to the END of FILE.

I tie the SDBM database file to a Perl Hash Table, for persistent random access indexing to my Flat File records of max file size 4 Gig each file, with unlimited nbr of files - or whatever nbr is practical for you. A single 4 GIG Flat File may contain multi-millions of records (Example: 5.6 million records where the record lengths are fixed at 760 characters). 4 GIG is a limitation of my older binary distribution of Win32 Perl 5.6.1 build 638 (ActiveState ActivePerl) because I can only use an integer value to randomly seek to a byte offset (+/- 2 GIG from TOP or END of file). Not everyone will experience this limitation.

I use Native Windows API, O/S specific I/O, but you could use portable: sysopen, close, sysseek, sysread, syswrite to navigate about the flat file and read/write data. I also use pack/unpack to read/write the data in or back out. TO BE CLEAR... You can use ANY programming language you like (e.g. Perl, Python, C++, etc.) with SDBM support, and ANY batch or GUI DB user-interface you like (e.g. portable Perl TK, Perl Win32-GUI by Aldo Calpini), and ANY file handling syntax you like (Win32API::File, portable sysopen/sysseek/sysread/syswrite/close, etc.).

My Flat file databases approach 1 terabyte in size, and 1 Billion "text" records, and are made up of a FILE SYSTEM of (DAT for Flat, PAG/DIR for SDBM) file extensions.

Please check out my latest comment additions in my 2nd message published on this thread, where I address Bitmap inclusion, and multi-user concurrency. That is a great topic for discussion, concurrency. The topic of data encoding/encryption/compression is also discussed.

When editing Flat File records, the changes are made "in place" overwriting existing data in the flat file record. A DELETE flag indicator field can be employed to mark records in both the Flat Files and SDBM files (for later BATCH deletion Server-side during off hours) for an application program to recognize as a BYPASS indicator until physically removed.

For ADDING/APPENDING records in a concurrent multi-user environment, to avoid race conditions, it is recommended that you employ a semaphore file for locking during these edits instead of placing a lock directly on the file to be edited. This "Perl" strategy is discussed in depth by an expert/author on the subject here: http://www.informit.com/articles/article.aspx?p=28258&seqNum=3 . For UPDATES to existing records within the database, I would use a RECORD LEVEL locking strategy. For Parent/Child relationships, I would design my DB user-interface to only allow edits to the child records when the parent record was locked for edit. The CHILD records would be housed in a separate FLAT FILE(s) and would have a foreign key index pointing to the PARENT. EXAMPLE: If you had a PARENT flat file of LOANS and a CHILD flat file of COLLATERAL securing those LOANS, such as motor vehicles, you could have a PRIMARY UNIQUE KEY on the CHILD flat file by VIN (Vehicle ID Number) and an ALT KEY w/DUPS on the LOAN NUMBER + UNIQUE SEQUENCE NBR (i.e. LoanNbr|SeqNbr) where the SEQ NBR is an incremented number starting at one(1) and is incremented by one(1) for each COLLATERAL record added to that LOAN. As a rule-of-thumb, you want to retain the ability to rebuild your binary SDBM indexes from the "text" data stored within your Flat File records while at the same time retaining the ties between CHILD records and their PARENT record. Thus, in the example just provided, you would want to store LOAN NBR within the Flat File CHILD records to tie back to the corresponding Flat File PARENT record.

A primitive attempt to index the records within a variable-length record, delimited field Flat File can be found here: https://docstore.mik.ua/orelly/perl4/cook/ch08_28.htm

The only problem with this primitive method/technique is that it only shows you how to randomly access a particular Flat File, variable-length record by the sequential record number. That is only useful if you know the sequential record number to go to. This does not give you the benefit of arbitrarily seeking to a particular record(s) based upon information contained within the fields of a record (such as the compound KEY: BirthDate, + LastNameFirst4Chars, + FirstNameInitial).

Replies are listed 'Best First'.
Re: Joint Database Technology
by erix (Parson) on Mar 24, 2015 at 21:53 UTC

    It seems more convenient to use a database that has already been programmed :)

    Have you ever made comparisons between your "building" and a regular DBMS? Comparisons in performance as well as in maintainance would seem interesting.

    I have to admit that I expect that on both counts your system might be the lesser solution but perhaps I'm wrong. What advantages do you see in your system?

    (and BTW, you're (of course) not the only one who thought of storing filepointers into a db. It was mentioned here (as an alternative to hash-based lookups) only a few weeks ago)

    ( 2015.03.26 Small update )

      MAIN/ROOT THREAD: http://www.perlmonks.org/index.pl?node_id=1121222

      The advantages I see to this Joint DB Technology are many fold.

      The problem with Flat File Databases (historically) has been that indexing to records was cumbersome/slow/a pain. Typically, a flat file would be read in its entirety (first to last record) each time an application program was launched where random access to the records was needed. As the file is being read in, a hash table is built in memory to hold the record offsets for random access while the current program is in use. This does nothing for your nerves, not does it lend itself to a concurrent multi-user environment.

      But with a persistent tie to an external Perl SDBM database containing the record offsets, random access to flat file records is immediately available, and I mean FAST!

      And you can use many Perl SDBM files as indexes to the same Flat File. Also, your key in the key/value pairs does not have to be of the same format. In other words, one(1) SDBM file can be used to hold many different indexes.

      I use the "key" to store the flat file fields I want used as indexes. I use the "value" to store the record offset (in bytes). The "key" in the key/value pair, can be one(1) or more fields and/or partial fields (perhaps delimited by a "|"). The "value" can be one(1) or more fields of data separated by a delimiting character such as a comma or pipe "|". An ALT KEY with DUPS can be managed too. Let's say we have a PRIMARY KEY on Social Security Nbr. Another useful KEY (ALT KEY w/DUPS) is shown in the example below.

      #-- YYYYMMDD #-- Key example: BirthDate|LastNameFirst4Chars|FirstNameInitia +l|StateCode #-- "19591219|Will|K|TX" #-- $KEY without a Seq Nbr is used to increment the number of rec +ords saved to the database #-- having a particular ALT KEY w/DUPS - in this example: "1959 +1219|Will|K|TX" $KEY=$BirthDate . "|" . $LastNameFirst4Chars . "|" . $FirstNameIn +itial . "|" . $StateCode; $Hash{$KEY}=0; #-- Now index the first record encountered in the Flat File datab +ase with this particular ALT KEY w/DUPS $num_recs = $Hash{$KEY}; $num_recs++; #-- i.e. one(1) $Hash{$KEY}=$num_recs; $newKEY=$KEY . "|" . $num_recs; #-- produces: "19591219|Will|K|TX|1" $Hash{$newKEY}= #-- The VALUE would be set to the byte offset o +f the Flat File record just indexed #-- Now index the second record encountered in the Flat File data +base with this particular ALT KEY w/DUPS $num_recs = $Hash{$KEY}; $num_recs++; #-- i.e. two(2) $Hash{$KEY}=$num_recs; $newKEY=$KEY . "|" . $num_recs; #-- produces: "19591219|Will|K|TX|2" $Hash{$newKEY}= #-- The VALUE would be set to the byte offset o +f the Flat File record just indexed #-- and so on...

      ALSO, SDBM is very very easy to use and has a 2 GIG storage abililty. Millions of record offsets can be stored for random access indexing to fixed-length file records. And you can use as many SDBM files as you need. But know this: that you can store multiple indexes (i.e. Key formats) within the same SDBM file. Also know this: That you don't have to store the byte offset to every record in your database if the database records are logically/physically sorted/grouped. What you can do is store the byte offset of the first record in a related/sorted group of records, random access the first record in the group, then sequentially access the remaining records in that group. Or, you can read into memory all the records within a group with just one(1) read statement execution (dozens of records to perhaps hundreds or a few thousand records in one READ). Then, using the UNPACK statement, you can break out each record (from the massive READ) into individual record array elements for further processing.

      Both Flat Files and SDBM are FREE/NO COST TECHNOLOGY that can be freely distributed. SDBM comes automatically with every distribution of Perl.

      SDBM is difficult to use by itself for database storage because of limitations on record size (something like 1000 bytes key/value pair maximum length combined). Flat Files can store huge records if needed, like COBOL files. Great for storing Bitmap images converted to inline text (See Aldo Calpini's Win32::GUI module for the INLINE BITMAP conversion utility).

      Flat files are text based. Not much can go wrong with them, whereas Perl SDBM files I believe are Binary. Well, they might get corrupted, so not as good an idea for storing your important data as it might be impossible to recover them. But when used only as index files, they can be rebuilt from the Flat File "text" data.

      I like to use Perl's formula-based MIMEbase64 encoding/decoding of stored data to make it humanly unreadable. My batch applications and user-interfaces do the conversion back to readable text on the fly. You can employ home-grown word-to-code encrypting/compression of your data using SDBM to store the key/value pairs for translation back from code to word. A link is provided later on in this thread by a contributor who found my posting at another site where I provide Perl code and the steps to employ encryption/compression with Perl SDBM, and where the word/code mappings are generated completely at random every time.

      Flat file databases and SDBM databases are easy to deploy and are portable. Right? And they are standalone. They do not rely on any other files such as Data Access Components (Drivers/Engines), DSNs, or any other gobble-d-goop that could become stepped on and must be current on any workstation on the Network. And, this database tandem system could be hosted on a Network Drive with the proper permissions for access to prevent copying and deleting.

      Finally, I think this could be considered a RDBMS? You could have a normalized flat file system of files and perform lookups to mapping tables (e.g. multiple instances of part_numbers within Flat File records mapped to a single instance of the corresponding part_descriptions within lookup tables) and even have one-to-many parent/child record relationships between Flat Files, using Perl SDBM indexing. Note: Always store the foreign key within the Child records to maintain the link between Parent and Children so that the SDBM indexing can be rebuilt from the Flat File records data.

      Someone brought up BITMAPS. Store them in the database, or store the filename in the database. I think I could store the BITMAP in a flat text file okay using an INLINE BITMAP utility that converts the Bitmap to a stream of text. I have used this before to hard code Bitmaps into my Windows GUI Perl Applications. The utility comes with Aldo Calpini's Win32::GUI Module. It can be ran as a command line utility or embedded within your Perl application program to display stored inline "text" bitmaps as true images (on the fly).

      Regarding multi-user concurrent access and data capacity, I have not tried the multi-user concurrency yet with NoSQL/ISAM Flat File/SDBM databases (lacking the opportunity). But I have loaded 5 million records of King James Version Bible verses of text to a single Flat File with Perl SDBM/tied Hash Table indexing to those 5 Million records. The random access lookup times to any verse were instantaneous. As fast as a Microsoft Jet (Red) Engine ODBC-enabled SQL Database of similar use. With Jet (Red), the engine used by MS-Access, I have loaded (via Dave Roth's: Perl Win32::ODBC module) 10 Million records to one *.MDB file using Jet 4.x format (*.mdb files) with compression and encryption turned on. Unfortunately, Win32::ODBC is no longer supported in the latest Perl distributions. Anyway, I am getting away from SQL and DAC/MDAC altogether, opting for NoSQL/ISAM/Embedded FlatFile/SDBM database systems.

        I do not see any advantages to what your propose over what an RDBMS offers. There is more to the story than just storing and retrieving data. $Clients want the data pivoted into all arrangements of reports. Standards such as PCI compliance shun using Personally Identifiable Information as non-encrypted keys. And then you have technologies such as Hadoop can perform map/reduce algorithms on flat files that span across multiple machines.

        What you have sounds cool, but not at the expense of ignoring current solutions that take a lot more into consideration than what you have here. What would sound cooler is a deploy-able implementation of what you propose -- and i certainly hope you don't limit your audience to just 1 platform.

        jeffa

        L-LL-L--L-LL-L--L-LL-L--
        -R--R-RR-R--R-RR-R--R-RR
        B--B--B--B--B--B--B--B--
        H---H---H---H---H---H---
        (the triplet paradiddle with high-hat)
        
Re: Joint Database Technology
by marinersk (Priest) on Mar 25, 2015 at 12:14 UTC

    I've done this. In fact, most DBMS systems grew out of this kind of good engineering and have taken it to the next level -- many times, in fact, to the point of being orders of magnitude ahead of these excellent fundamentals.

    These days, free, multiplatformic, SQL-complaint RDBMSs offer lots of pre-built functionality that I don't have to maintain. But for a few really exceptional cases anymore, they've proven to be as fast -- sometimes faster -- than home-grown solutions when applied to large datasets, and eliminate most of the development related to the data engine.

    This not only reduces the cost and speed of development, but also the risks inherent to any software development activity.

    I'm not saying an RDBMS is always the right answer -- far from it. It is my considered opinion that far too many people jump toward a database solution far too quickly, when a faster, more efficient solution is right in front of them (often involving the use of Perl features like hashes and such).

    But once you've decided to go with a DBMS, most -- not all, but most -- of the time, a pre-built RDBMS offers so many advantages that a home-grown, rudimentary DBMS such as you have described simply cannot compete with.

    I'm fundamentally a data and algorithms guy -- always have been. I've designed and refined data storage, retrieval, and indexing routines for most of my career. And I was slow to adopt SQL in any form, but where they've gone with the technology is amazing even to me -- and it's hard to impress me in the data/algorithm space.

    What you've done is impressive, efficient, elegant, and represents the very best in applying engineering principles to solving a fairly general-use case. I fervently hope and pray this kind of talent is not lost in our profession, and it is heart-warming to see it thrives yet.

    But the world of general-purpose data storage has moved far past these fundamentals, and most of your stated advantages reflect a lack of understanding of where the state of the art has gone whilst you weren't looking.

    I painfully admit that I once stood where you now stand -- rightfully proud of excellent engineering efforts and what it has produced, and all the while having no idea what I was about to find had been going on out in the rest of the world which would render my efforts nearly irrelevant.

    I wish for you a gentler, and more importantly, speedier, recovery than I experienced. The sooner we accept the world for what it is, the more likely we can get back to doing things both great and small to continue to improve it.

      Acknowledging all of your points, Mariners, here’s a good, every-day example of a distinction that I might draw:   “given the requirement to ‘store large images,’ do you store those images in your RDBMS, or do you instead store filenames?”

      There’s no bright-line rule.   It depends on many things, including how well your particular database implementation handles “large BLOBs.”   Also to be considered is the fact that any file-system is also “a database of sorts,” which is extremely adept at storing variable-sized objects using a single key otherwise known as a “file name.”   Both approaches are defensible and we have all seen both of them done.

      If the files which contain the data are enormous, and/or if they are already being used for other purposes by other existing applications, then it might well not be appropriate to move these data into an RDBMS, but, instead, to use the RDBMS as an index.   There is still a lot of high-volume data processing which requires the use of sorted files, with sorted updates being applied to those always-sorted remains-sorted files, specifically to avoid random-access.   But an RDBMS might still be useful for quickly and directly finding the location (exact, or approximate) of whatever data is being sought, thereby allowing the records to be queried randomly.   It is an admitted compromise, to be judiciously employed if and when the case arises.

        Agreed on all points.

        Man, that's twice in one year. We should check and see if Armaggedon is happening or something.

        In response to "Do you store images in your RDBMS, or do you instead store filenames?” In my tandem: Perl SDBM(random access indexing)/Flat File Databases(text data storage, fixed-length records) I store Bitmaps as text. Then, on the fly, I convert those text representations of images back into real images to display them to the end-user. This is a great security feature. This can be done on Windows O/S systems with Win32 Perl and the InLineBitMap conversion utility that comes with the Win32-GUI module.
Re: Joint Database Technology
by flexvault (Monsignor) on Mar 25, 2015 at 16:17 UTC

    erichansen1836,

      Please tell me I'm not the only Perl user in the Universe doing this?

    Welcome...

    Several years ago, I wrote a pure-Perl replacement for BerkeleyDB. My reasons were not about performance, but about licensing fees. Oracle bought SleeyCat and so controlled the licensing. For our clients ( Fortune 1000 companies ) the fees for Oracle's BerkeleyDB were many times the fees for our products.

    This doesn't seem to be your problem, but you may want to consider 2 things.

      • Can your product work for multiple simultaneous users? and
      • What is the performance for more than 1 million records?

    If you are only going to use your product internally and only by you then this isn't a concern. But, if you are going to incorporate this with a commercial product than this will be very important. YMMV.

    Our 1st client has a PurePerlDB database of more than 100 million records and has at times more than 1,000 users simultaneously using the data base. Big Data is real today and benchmarks of 10,000 records just don't tell the story.

    Good luck, and your not alone!

    Regards...Ed

    "Well done is better than well said." - Benjamin Franklin

      Our 1st client has a PurePerlDB database of more than 100 million records and has at times more than 1,000 users simultaneously using the data base. Big Data is real today and benchmarks of 10,000 records just don't tell the story.

      Good luck, and your not alone!

      Regards...Ed

      Ed, thanks for the productive comment. Back 17 years ago, around 2000, I was asked by Bank of America to write an invoice Flat File record editor application in Win32 Perl (with a native Windows, Win32::GUI module user-interface). Back then I had not discovered tandem use of Flat Files with persistent SDBM indexing to the Flat File records. I remember how my application would have to read in the entire Flat File (at launch) and create the indexes in memory each time. This was a bit of a pain for my end-user. Regards...Eric
Re: Joint Database Technology
by Your Mother (Bishop) on Mar 25, 2015 at 16:17 UTC
    Perhaps it is a new invention nobody has thought of?

    Call me cynical and cranky but this sounds a lot like site:perlmonks.org aXML to me. If you don’t have code to look at and try then this comes off as a peculiar boast, apropos of nothing. Home rolled systems are only interesting to others if the others either share exact specialization concerns or the home rolled system comes with tests, examples, documentation, and a compelling reason to investigate it rather than the many existing alternatives with same.

    Kind of hard to share with others…

    No, it’s not. Put it in a public RCS, set it up as a standard CPAN-style Perl distribution, and it shares itself.

Re: Joint Database Technology
by Laurent_R (Canon) on Mar 24, 2015 at 22:16 UTC
    Hmm,

    Your post seems to be interesting, but is pretty much impossible to digest.

    Please provide a rightly formatted post after having looked to these guidelines: Markup in the Monastery

    Je suis Charlie.
Re: Joint Database Technology
by karlgoethebier (Monsignor) on Mar 25, 2015 at 17:59 UTC
    "...a new invention nobody has thought of?"

    My first thought: Why don't you show an example?

    Best regards, Karl

    «The Crux of the Biscuit is the Apostrophe»

      Code example you have requested:

      This Perl program retrieves 5 verses of King James Version Bible text from a large Flat File (with fixed-length, "text" records) by random access lookup.
      The Flat File contains 180 complete copies of the KJV Bible, with a bogus translation number (tr) assigned to each Bible copy (tr = 1 to 180) to make a unique key: {translation_nbr + book_nbr + chapter_nbr + verse_nbr}.
      Record offsets (in bytes) are persistently stored in a binary Perl SDBM database file, of key/value pairs, tied to a program hash table. The value is the offset.
      The key is {tr + bk + chp + ver} numbers combined/concatenated.
      If $offset is a negative value, seek from BOTTOM/END of file.
      If $offset is a positive value, seek from BEGIN/TOP of file.
      Each Bible contains 31102 verses of text, of max length 528 charater each.
      But with the compound index {tr + bk + chp + ver} added to the Bible text, for the purpose of proving the random access is working, and MIMEbase64 encoding applied (to hide the Bible text), the fixed length records have become 760 characters each. Decoding will occur as records are read.
      The Flat File is just under 4 GIG. The SDBM file just under 1 GIG.
      There are over 5 Million records each, in both the Flat File and SDBM file. (180 copies of the Bible times 31102 verses per Bible)
      Flat File, random access, record lookup, is instantaneous.
      You can use Perl Portable Code: sysopen, syswrite, sysseek, sysread.
      But the below example is Windows O/S specific Perl Code.
      This example is a batch application process (no user front-end), having 5 hard-coded lookup keys.
      You can build a user-interface to instead accept the lookup keys from user input: either typed in, or selected from a GUI widget of preloaded values {tr, bk, chp, ver}.
      A RANGE of values could even be selected to print Bible verses for an entire Book (ex. tr="134", bk="01" i.e. Genesis)

      (NOTE: Pls know we are not promoting any religion here. The KJV Bible was selected because it is in the public domain, and because it is logically segregated making it a good test file which can easily be copied over-and-over to fill up as many Flat Files as is desired for testing.)

      Dozens of Flat Files, each with 180 complete copies of the Bible, could be preloaded, and your application program designed to access any one of them based upon the different set of distinct bogus translation numbers (tr) contained within each Flat File (and its associated SDBM binary file tied to a hash table). Not shown here, was the initial code used to load the Flat File with records, and load the SDBM file with key/val pairs.

      To be clear: This "random access" technique requires no reading in of the Flat File records sequentially, nor does it require reading in rows/records sequentially from the binary SDBM file of key/val pairs - to load them into the Hash table. As soon as the below code is launched, the Bible verses are randomly accessed and printed to the screen in a split second.

      use Win32API::File 0.08 qw( :ALL ); use Win32; use SDBM_File; use Fcntl; use MIME::Base64 qw(decode_base64); $PWD=Win32::GetCwd(); tie( %BibleVersesIDX, "SDBM_File", '.\BibleFlatFile_760_31102_180_IDX' +, O_RDONLY, 0444 ); if (tied %BibleVersesIDX) { print "BibleVersesIDX Hash now tied to ext +ernal SDBM file\n\n"; } else { print "Could not tie BibleVersesIDX Hash with external SDBM fil +e - Aborting\n\n"; die; } $hFILE = createFile("$PWD\\BibleFlatFile_760_31102_180.dat", "r"); foreach $key ("00101001001", "09066022021", "09101001001", "1800100100 +1", "18066022021") { $offset=$BibleVersesIDX{$key}; if ($offset < 0) { $pos=SetFilePointer( $hFILE, $offset, [], FILE_END); } else { $pos=SetFilePointer( $hFILE, $offset, [], FILE_BEGIN); } ReadFile( $hFILE, $Buf, 760, [], [] ); $decoded_Buf=decode_base64($Buf); $decoded_Buf=~s/ *$//; print $decoded_Buf . "\n\n"; } exit; END { CloseHandle( $hFILE ); untie( %BibleVersesIDX ); sleep 5; }

        Thank you very much erichansen1836 for providing your example.

        As you wrote, i requested it. So i take up this challenge and i hope very much that i don't make a fool of myself (because i'm really no database expert):

        "Random access lookup is instantaneous !!! FAST!"

        Very nice - if so. But unfortunately i can't verify/reproduce this because i don't have any data for benchmarking.

        And traditionally this effort is left to the author.

        I've been reading your code over and over again but i can't see any benefit for the moment.

        But as you may have noticed, i rely very much on my intuition. Some might say i guess sometimes.

        So i guess that it would be perhaps a good idea to read a bit about Star schema and all the related stuff you may find.

        Just an idea - and i hope it isn't misleading.

        Best regards, Karl

        «The Crux of the Biscuit is the Apostrophe»

        Please Update your post to use  <c> ... </c> or  <code> ... </code> tags around code, data and input/output. Please see Markup in the Monastery and Writeup Formatting Tips. Please do yourself (and your fellow monks) an enormous favor and use  <code> tags in future. (Update: Note that just a single  <c> ... </c> pair would have been sufficient rather than a million  <p></p> paragraph tag pairs, and would have made the whole thing immediately downloadable, too!)


        Give a man a fish:  <%-(-(-(-<

Re: Joint Database Technology
by erichansen1836 (Acolyte) on Sep 01, 2017 at 17:59 UTC

    I am providing below a code snippet replacement for the JOINT DATABASE TECHNOLOGY - DEMO, KJV Bible Navigator software. I have rewritten the TreeView Double Click EVENT so that instead of reading in each verse of a chapter individually (a read executed for each verse), I now have the code read in the entire chapter in one read execution. I use the unpack statement to separate out the individual verses. This I'm guessing is more efficient code? and may work faster across a Network? Anyway, it is here if you want to use it. Just delete the TVDblClick event from the original code and replace with the TVDblClick event code provided here. If anyone has access to a Network drive and wants to performance test the two different read methods (1 read per chapter vs. 1 read for each verse of a chapter), then that would be helpful for us to know which is faster.

    ################ sub TVDblClick { ################ my ($self, $x, $y) = @_; my $node = $self->HitTest($x,$y); $self->Select($node); my $parent_node = $self->GetParent($node); if ($node == 0 || $parent_node == 0) { return; } $RE->Text(""); my %parentinfo = $self->ItemInfo($parent_node); my ($bk, $bkname) = split(/:/,$parentinfo{-text}); my %nodeinfo = $self->ItemInfo($node); my ($abbrev, $string) = split(/ /,$nodeinfo{-text}); my ($chp, $range) = split(/:/,$string); my $outputfile="$PWD\\KJV_Bible_" . $bkname . "_Chp_" . $chp . ".rtf"; my $ret=0; open(BibleRTF,"> $outputfile") || do {$ret=1;}; if (! $ret) { BibleRTF->autoflush(1); #-- flush the output buffer each print } else { Win32::GUI::MessageBox($W1,"Can't open file\n$outputfile\nfor outpu +t\n$!", "KJV Bible Navigator - Error",16,); return; } my $key=$bk . "|" . $chp; my ($offset, $nbr_verses) = split(/,/,$BibleIDX{$key}); my $pos=SetFilePointer( $hFILE, $offset, [], FILE_BEGIN); #-- random a +ccess unless ( $pos ) { my $error = fileLastError(); my $msg = "Can't set file pointer at byte offset $offset within:\n" + . "$PWD\\KJV_Bible_SDBM.dat" . "\nat Book of $bkname chapter $chp verse 1\n" . $error; Win32::GUI::MessageBox($W1,$msg,"KJV Bible Navigator - Error",16,); close(BibleRTF); return; } my $BIB_Tmpl = ""; #-- build a template to unpack an entire chapter o +f verses for (my $i=1; $i<= $nbr_verses; $i++) { $BIB_Tmpl = $BIB_Tmpl . "A528, "; } chop $BIB_Tmpl; chop $BIB_Tmpl; #-- remove trailing ", " $nbr_chars=(528 * $nbr_verses); my $buff = "Hello Dolly"; $ret=ReadFile( $hFILE, $buff, $nbr_chars, [], [] ); #-- read in a whol +e chapter unless ( $ret ) { my $error = fileLastError(); my $msg = "Can't read input file:\n" . "$PWD\\KJV_Bible_SDBM.dat" . + "\nat Book of $bkname chapter $chp verses 1 to $nbr_verses\n" . + $error; Win32::GUI::MessageBox($W1,$msg,"KJV Bible Navigator - Error",16,); close(BibleRTF); return; } my @verses=(); @verses=unpack($BIB_Tmpl,$buff); print BibleRTF '{\rtf1\ansi\ansicpg1252\deff0\deflang1033\deflangfe103 +3' . '{\fonttbl{\f0\fswiss\fcharset0 Tahoma;}}' . '{\colortbl ;\red255\green0\blue0;}' . '\viewkind4\uc1\pard\f0\fs18' . "\n"; for (my $j=0; $j<$nbr_verses; $j++) { Win32::GUI::DoEvents(); #-- keep window from perhaps freezing u +p $verses[$j]=~s/ *$//; #-- remove trailing spaces from ea. ver +se $ver=$j+1; #print BibleRTF '\ul\b\i0\highlight1 ' print BibleRTF '\ul\b0\i\highlight0 ' . "$bkname $chp:$ver (KJV)" . '\par\ulnone\b\i0\highlight0' . $verses[$j] . '\par\par' . " +\n"; } print BibleRTF '}' . "\n"; close(BibleRTF); $RE->Load("$outputfile"); #-- Perform some Window Maintenance. #-- We don't want to Maximize Window because end-user may have adjuste +d size. Window1_Maint(); }
Re: Joint Database Technology
by erichansen1836 (Acolyte) on Jun 17, 2017 at 16:52 UTC

    Flat File Databases Indexed by SDBM Databases - An ISAM, NoSQL, Embedded Database System:

    Follow first post in thread to find code examples: http://www.perlmonks.org/?node_id=1121222

    SDBM databases of Key/Value pairs (tied to program hash tables) may be used to persistently index the fixed-length records of a "text" Flat File database for immediate random access. Historically, Flat File databases and SDBM databases have proven to be relatively weak when used alone, but when combined, the two offer a relatively strong relational database system. The binary SDBM files can store as the KEY (in the Key/Value pair), one or more fields and/or partial fields (concatenated together) contained within the Flat File, fixed-length records. The VALUE would hold the byte location offset of each record indexed, for positioning the file pointer for Read/Write operations. Edits to records are made "in place" either overwriting the existing record in its entirety, or overwriting only a single field contained within a record. Multiple Indexes (varying Key formats and their accompanying byte offset, Values) may be stored in a single SDBM file. Example: a Unique Primary Key Index which may be used is Social Security Number, and relative to that, an Alternate Key Index (with Duplicates) may be used on a combination of the fields and partial fields {BirthDate|LastNameFirst4Chars|FirstNameInitial|SeqNbr} where Sequence Number(SeqNbr) is an incremented number used to make each duplicate instance of the KEY {BirthDate, LastNameFirst4Chars, FirstNameInitial} unique. This database system would be most practical and easy to implement for Read Only, Data Warehousing and Data Marts, but with the addition of exclusively locked and released semaphore files, employed to prevent race conditions from occurring to protect the Flat File data source, a concurrent multi-user, Read/Write Database System could conceivably be implemented. A Read/Write Database System of this sort would need to have controlled access by a Front-End Database Application User-Interface which enforced a manual record locking and release strategy, and which managed the use of semaphore files.

    SEE Semaphore Files Perl article at: http://www.informit.com/articles/article.aspx?p=28258&seqNum=3

    PARENT/CHILD one-to-many record relationships may also be managed. The Parent records would be stored in a separate Flat File from that of the Children. Example: If the Parent records are LOANS, and the Child records are the individual COLLATERAL (say motor vehicles) securing those loans, then the Unique Primary Key for the Child records could be on VIN (Vehicle Identification Number), and an Alternate Key with Duplicates could be the Loan Number of the Parent record. Added to the Loan Number (Alternate Key with Duplicates), would be a sequence number incremented for each Child collateral item added to the database for each Loan (Loan_Nbr|SeqNbr). Thus, the Children are tied back to the Parent by the Loan Number (and vice versa). You would also want to store the LOAN NBR of the parent records within each of their child records so that you maintain the ties between parent and child Flat File records in the event the binary SDBM indexing becomes corrupt and needs to be rebuilt from the Flat File data.

    Redundant data typically stored in Flat File databases can also be eliminated. Now, a Part Number alone need be stored in each record of a Flat File typically containing both Part Numbers and Part Descriptions. A Look Up of a single instance of the Part Description (by Part Number) is all that is required.

      ... can really be ...
      ... would be ...
      ... could be designed to ...

      Apparently, Joint Database Technology is still a castle in the air, isn't it?

      I don't see a single item in your argumentation that isn't very likely better (and /much/ better) done by an already existing system like PostgreSQL, which already exists(!), has been developed and improved on for 20+ years(!), and is standard-compliant like few other systems. There is a large community of people improving postgres, producing a new version (with new features) every year. Bugs often get fixed within 24 hours. PostgreSQL is completely free and you may use it to build a closed-source system.

      Here is a challenge: can you publish here such a system of your design, giving full code, and using data in the form of free text files (or even self-generated ones), so that any one of us can reproduce it and test its performance? (multi-platform, please: windows-only is not good enough).

      If you do that I'll try to counter it with a postgres-based system to parallel it. Only then can we see what are the pros and cons of your SDBM/hash/perl/text-system versus poor old conventional PostgreSQL.

        Think outside the box. Gene Cranz (NASA Flight Director - Apollo 13) "I don't care what anything was designed to do, I care about what it can do".

      erichansen1836:

      Sounds much like another implementation of an ISAM-like system, an early step along the road to relational database systems.

      ...roboticus

      When your only tool is a hammer, all problems look like your thumb.

        Original Thread to follow for Perl Code examples and initial discussion/description = http://www.perlmonks.org/?node_id=1121222

        It has been pointed out that what I have referred to here on this thread as Joint Database Technology (Flat "text" Files/SDBM Files tied to Hash Tables) is really a type of NoSQL/ISAM (Indexed Sequential Access Method) technology.

        The records in the Flat Files do not need to be maintained in a sorted record order either, although this may be beneficial for sequential access. For random access, it is not necessary. HOWEVER..YOU COULD sort the Keys in the hash table tied to any of the SDBM files used for random access indexing. Then process the unsorted Flat File in sequential order because you access each record randomly by the sorted KEYs.

        What I have done recently which works well is to create an SDBM file with only the byte offsets stored which point to the first verse in each chapter of each book of the Bible. I also store the number of verses within each of those chapters in the SDBM file, so that I read the first verse of each chapter of each book randomly, then read the rest of the verses in a specific chapter sequentially from there. This makes the SDBM file much smaller in size since I am not storing a byte offset for every verse (but only the first verse in each chapter).

        My latest enhancement has been to read an entire chapter of Bible verses in one(1) read statement execution, and use the unpack statement to break out each verse into an array for processing. This code enhancement (TreeView DblClick Event) was posted to this thread for the KJV Bible Navigator DEMO software posted here. DEMO refers to a demonstration of the Joint Database Technology technique, not that the Perl code posted here is only a DEMO of a more fully functional KJV Bible Navigtator software which might exist. This software is not for sale, but only provided to demonstrate the FlatFile/SDBM joint/dual/tandem database system technology technique within a useful application program. This code could be tweaked to make it display a database of Customers/Invoices/Items within a TreeView/RichEdit widget GUI user-interface. Or whatever data you like.

Re: Joint Database Technology
by sundialsvc4 (Abbot) on Mar 25, 2015 at 00:18 UTC

    Oh, I definitely understand what you’re getting at ... and you’re absolutely correct that your approach is proper.   (No, it isn’t original, but very few engineering solutions ever are.)

    The obvious advantage of your approach is that the “terabytes of data” do not have to be moved, copied, or duplicated.   The database, and/or hash-tables or what-have-you, serves as a convenient index into this “enormous data source,”

    Actually, when “inconveniently-massive amounts of data” are involved, this sort of approach is actually ... fairly typical.   You do not have to move data into, say, “an SQL database,” in order to effectively use “an SQL database” to index it.   The only design-concern is that you need to take care that the [SQL database ...] index doesn’t duplicate the content that it is meant to index.   (This might, for instance, mean that the index is, by-design, ‘uncertain.’)   You must also ensure that the external-index(es) ... whatever (it is) | (they are) ... remains “current-enough to be both ‘useful’ and ‘not misleading.’”

Re: Joint Database Technology
by Anonymous Monk on Aug 31, 2017 at 16:05 UTC

    If anyone wishes to try the KJB Bible Navigator software source code uploaded at this thread and needs the Flat File database and the SDBM database, if you can provide me your email address or provide me with a site to post the files for your to download from, I will do that (which might be best so that anyone can download them at will)

        https://raw.githubusercontent.com/scrollmapper/bible_databases/master/csv/t_kjv.csv This site will do for a download source, but of course you will need to do the ETL operations yourself to put the data into the correct format for the KJJ Bible Navigator software Win32 Perl source code to correctly read.
Re: Joint Database Technology
by erichansen1836 (Acolyte) on Aug 29, 2017 at 17:23 UTC

    BELOW fully functional, Windows(tm) O/S platform specific, PERL CODE, is a demonstration application of the Joint Database Technology/Methodology. The application program presents an entire database of King James Version Bible Verses for the end-user to navigate and view within a GUI user-interface. The user is shown a summary of this information in a scrolling TREEVIEW widget (i.e. The 66 Books of the Protestant KJV Christian Bible, and the Chapter numbers within each Book). Once the end-user DBLclicks their mouse on a specific chapter within a specific book, the verses for that book/chapter are displayed within a scrolling RichEdit widget. Please read the comments section at the top of the application program to understand the format of the Flat File database, and the SDBM database used for indexing.

    This database is a small database, and someone might ask why not just load the whole Bible into memory? TRUE, but that still might be a tad bit slow (noticeable time lapse/delay at launch) during the initial loading, which is not very professional. Besides, this is just a DEMONSTRATION of the Joint Database Technology concept. If you want to really check the POWER of this database retrieval speed on MILLIONS of ROWS/RECORDS, then you can load 5.6 million records (180 complete copies of the KJV Bible) as I demonstrated in my original CODE posting into your FLAT FILE, with SDBM indexing to the first verse within each chapter of each book of each bogus translation (1 to 180). Access times will be INSTANTANEOUS. What you can do (SIMPLY) is just HARD CODE the translation number for LOOKUP within the KJV Bible Navigator software I provided instead of having to add more functionality to it. Then it will act like it is just looking at one Bible copy instead of 180 copies, yet it will be fetching the rows from within the 5.6 million rows/records within the Flat File.

    A screen snapshot of the below JOINT DATABASE TECHNOLOGY, DEMO software GUI application user-interface can be viewed here: http://s1345.photobucket.com/user/siamese_charlie/media/KJV_BIBLE_NAVIGATOR_zpsybh0dwzf.jpg.html

    ###################################################################### +########## #-- NAME: KJV_Bible_SDBM.pl (or compiled to .exe) #-- #-- AUTHOR: Eric Hansen U.S.A #-- #-- DATE: August 29, 2017 #-- #-- LANGUAGE: Win32 Perl - ActiveState ActivePerl v5.6.1, binary buil +d 638 #-- Win32 GUI Module (by Aldo Calpini) release 1.02 #-- #-- COMPILER: IndigoSTAR Perl2EXE v5.03, Win32 Perl Application Compi +ler #-- #-- FUNCTION: KJV Bible Navigator Software. FlatFile/SDBM Database Ve +rsion. #-- DB User-Interface is a TreeView/RichEdit set of GUI wid +gets. #-- #-- DATABASE: 3 input Files (JOINT DATABASE TECHNOLOGY - ISAM/NoSQL): #-- #-- KJV_Bible_SDBM.dat (16,037 KB) Fixed-length(528 charact +ers) #-- records (no CR/LF), Flat File of 31102 KJV Bible ve +rses #-- extracted from a total of 66 books and 1189 chapter +s. #-- KJV_Bible_SDBM.dir (4 KB) SDBM Binary File (part 1 of + 2) #-- KJV_Bible_SDBM.pag (128 KB) SDBM Binary File (part 2 of + 2) #-- Both used for random access indexing within the Fla +t File #-- to the byte offset of the first verse within each c +hapter. #-- Verses within a Chapter are read sequentially from +there. #-- These 3 files (named as shown) must reside in the appli +cation #-- directory with program file KJV_Bible_SDBM.pl or .e +xe #-- if compiled to a standalone executable. #-- #-- OUTPUT: KJV_Bible_Genesis_Chp_3.rtf would be a Rich Edit (Wordp +ad) output #-- file created in the Program/Application DIR containing +all the #-- verses for the Book of Genesis, Chapter 3. This output +file is #-- automatically created for each Book&Chapter the end-use +r selects. #-- #-- HASH: Format of SDBM tied to hash table BibleIDX (for Books 1 + to 66) #-- KEY VALUE DESCRIPTION #-- ======================================================= +====== #-- ... #-- 10 II Samuel,2Sa,24 Bk10 = name,abbrev,nbr_c +hps #-- 10|1 4236144,27 Bk10|Chp1 = offset,nbr_ +verses #-- ... #-- 10|10 4351248,19 Bk10|Chp10 = offset,nbr_ +verses #-- ... #-- 10|24 4589904,25 Bk10|Chp24 = offset,nbr_ +verses #-- ... #-- #-- ABORTED: Should the program abort, run from a command prompt to +see error. #-- This would most likely occur if one or more of the 3 da +tabase #-- files are missing from the application directory, or th +ey have #-- been renamed. #-- #-- NO VERSES #-- DISPLAY: If you do not see Bible verses displayed in the RichEdi +t widget #-- after you have DBL-clicked your mouse on a particular c +hapter #-- within the TreeView widget, it is likely due to the ass +ociated #-- *.rtf output file already existing and having been manu +ally #-- set to a READ ONLY status. If the file exists, it must +have #-- WRITE permission. An Error Msg Box will pop up on the s +creen. #-- To correct this problem, either delete or rename the *. +rtf file. #-- If you wish to write personal notes within any of the * +.rtf #-- files generated, and prevent them from being stepped on + #-- (i.e. overwritten), then instead of making the file(s) +READ ONLY, #-- simply rename them. Example: #-- KJV_Bible_Genesis_Chp_3.rtf to KJV_Bible_Genesis_Chp3_E +dited.rtf #-- Or, you can make a subdirectory and store your edited f +iles there ###################################################################### +########## use Win32; use Win32::GUI; #-- module extension by Aldo Calpini. Native Windo +ws GUI. use IO::Handle; use SDBM_File; use Fcntl; use Win32API::File 0.08 qw( :ALL ); $SFont = new Win32::GUI::Font( -name => "Courier New", -size => 8, -height => -11, -weight => 700 ); $M1 = new Win32::GUI::Menu( "&File" => "File1", " > &Exit" => "Exit1", "&Help" => "Help1", " > &About" => "About1", ); $W1 = new Win32::GUI::Window ( -title => "KJV Bible Navigator (FlatFile/SDBM Database Version) +", -menu => $M1, -name => "Window1", -minsize => [400, 200], ); $TV = $W1->AddTreeView ( -name => "TV", -font => $SFont, -left => 10, -top => 5, -width => 180, -height => $W1->ScaleHeight()-10, -lines => 0, -rootlines => 1, -buttons => 1, -visible => 1, -checkboxes => 0, -onMouseDblClick => \&TVDblClick, ); $RE = $W1->AddRichEdit( -name => "RE", -height => $W1->ScaleHeight()-10, -width => $W1->ScaleWidth()-205, -wrap => 1, -top => 5, -left => 195, -style => WS_VISIBLE | WS_VSCROLL | ES_AUTOVSCROLL | ES_MULTILINE +, -readonly => 1, ); ######################## ######################## ### Initialization ### ######################## ######################## $DOS = Win32::GUI::GetPerlWindow(); Win32::GUI::Hide($DOS); $PWD=Win32::GetCwd(); #-- program(p)/current(c) working(w) directory(d +) location $W1->Show(); $W1->Maximize(); Window1_Maint(); Database_Connect(); Load_TreeView(); $W1->Maximize(); Window1_Maint(); ####################### ####################### ### Event Handler ### ####################### ####################### Win32::GUI::Dialog(); #-- Enter event handler, and wait for end-user +responses #-- Logical End-of-Program is Here, although the END{} routine is perf +ormed last #-- as cleanup. ###################################################################### +########## ###################################################################### +########## ############ SUBROUTINES ## +########## ###################################################################### +########## ###################################################################### +########## ###################### sub Database_Connect { ###################### $hFILE = createFile("$PWD\\KJV_Bible_SDBM.dat", "r"); unless ( $hFILE ) { die "Can't open Flat File: $PWD\\KJV_Bible_SDBM.dat (ERROR: ", fileLastError(),")\n"; } tie( %BibleIDX, "SDBM_File", '.\KJV_BIBLE_SDBM', O_RDONLY, 0444 ); unless ( tied %BibleIDX ) { die "Can't tie hash tbl to SDBM Files: $PWD\\KJV_Bible_SDBM.pag (& . +dir) $!"; } } ################### sub Load_TreeView { ################### $TV->Clear(); $RE->Text(""); for my $bk (1 .. 66) { my ($name, $short_name, $nbr_chps) = split(/,/,$BibleIDX{$bk}); my $node = $TV->InsertItem(-text => "$bk:$name"); #-- insert a Par +ent node for my $chp (1 .. $nbr_chps) { Win32::GUI::DoEvents(); #-- keep window from perhaps freezing up my $key = $bk . "|" . $chp; my ($offset, $nbr_vers) = split(/,/,$BibleIDX{$key}); $TV->InsertItem(-parent => $node, -text => "$short_name $chp:1-$nb +r_vers"); } } } ################### sub Window1_Maint { ################### #-- Perform some Window Maintenance. A bit redundant (and overkill?) +perhaps. #-- Not sure how much of this is necessary? Better safe than sorry. #-- Does not hurt performance. $W1->BringWindowToTop(); #-- Brings window to the foreground $W1->SetForegroundWindow(); #-- Brings window to the foreground $W1->SetActiveWindow(); #-- Activates window $W1->Redraw(1); #-- Same as InvalidateRect $W1->InvalidateRect(1); #-- Redraw the Window $W1->Update(); #-- similar to Redraw and InvalidateRect $W1->SetFocus(); } ###################################################################### +########## ###################################################################### +########## ############ EVENTS ##### +########## ###################################################################### +########## ###################################################################### +########## ################ sub TVDblClick { ################ my ($self, $x, $y) = @_; my $node = $self->HitTest($x,$y); $self->Select($node); my $parent_node = $self->GetParent($node); if ($node == 0 || $parent_node == 0) { return; } $RE->Text(""); my %parentinfo = $self->ItemInfo($parent_node); my ($bk, $bkname) = split(/:/,$parentinfo{-text}); my %nodeinfo = $self->ItemInfo($node); my ($abbrev, $string) = split(/ /,$nodeinfo{-text}); my ($chp, $range) = split(/:/,$string); my $outputfile="$PWD\\KJV_Bible_" . $bkname . "_Chp_" . $chp . ".rtf"; my $ret=0; open(BibleRTF,"> $outputfile") || do {$ret=1;}; if (! $ret) { BibleRTF->autoflush(1); #-- flush the output buffer each print } else { Win32::GUI::MessageBox($W1,"Can't open file\n$outputfile\nfor outpu +t\n$!", "KJV Bible Navigator - Error",16,); return; } print BibleRTF '{\rtf1\ansi\ansicpg1252\deff0\deflang1033\deflangfe103 +3' . '{\fonttbl{\f0\fswiss\fcharset0 Tahoma;}}' . '{\colortbl ;\red255\green0\blue0;}' . '\viewkind4\uc1\pard\f0\fs18' . "\n"; my $key=$bk . "|" . $chp; my ($offset, $nbr_verses) = split(/,/,$BibleIDX{$key}); my $rec = "Hello Dolly"; my $txt = "Hello Dolly"; for (my $ver=1;$ver<=$nbr_verses;$ver++) { Win32::GUI::DoEvents(); #-- keep window from perhaps freezing u +p if ($ver == 1) { my $pos=SetFilePointer( $hFILE, $offset, [], FILE_BEGIN); #-- ran +dom access unless ( $pos ) { my $error = fileLastError(); my $msg = "Can't set file pointer at byte offset $offset within +:\n" . "$PWD\\KJV_Bible_SDBM.dat" . "\nat Book of $bkname chapter $chp verse $ver\n" . $er +ror; Win32::GUI::MessageBox($W1,$msg,"KJV Bible Navigator - Error",1 +6,); last; } } $ret = ReadFile( $hFILE, $rec, 528, [], [] ); #-- sequential access + unless ( $ret ) { my $error = fileLastError(); my $msg = "Can't read input file:\n" . "$PWD\\KJV_Bible_SDBM.dat +" . "\nat Book of $bkname chapter $chp verse $ver\n" . $er +ror; Win32::GUI::MessageBox($W1,$msg,"KJV Bible Navigator - Error",16 +,); last; } #-- Next, we want to trim the length of $rec before printing. #-- Buffer $rec is initialized to fixed-length 528, and can't be tr +immed. $txt=sprintf("%s", $rec); #-- required step in removing trailing sp +aces $txt=~s/ *$//; #-- remove trailing spaces or you can ... $txt=~s/\s+$//; #-- remove trailing spaces (redundant here just to +show) #$txt=~s/^\s+//; #-- if we had needed to remove leading spaces, if a +ny #print BibleRTF '\ul\b\i0\highlight1 ' print BibleRTF '\ul\b0\i\highlight0 ' . "$bkname $chp:$ver (KJV)" . '\par\ulnone\b\i0\highlight0' . $txt . '\par\par' . "\n"; } print BibleRTF '}' . "\n"; close(BibleRTF); $RE->Load("$outputfile"); #-- Perform some Window Maintenance. #-- We don't want to Maximize Window because end-user may have adjuste +d size. Window1_Maint(); } ################## sub About1_Click { ################## my $about_text="Written by Eric Hansen, U.S.A., August 29, 2017\n" . "In the Win32 PERL language - ActiveState ActivePerl v5.6.1, build +638\n" . "Compiled with the IndigoSTAR Perl2Exe compiler v5.03\n" . "Perl Win32-GUI module (by Aldo Calpini) release 1.02\n" . "Expand a Book, then DblClick a Chapter to view it.\n" . "Close this message box to proceed."; my $about = "About - KJV Bible Navigator - FlatFile/SDBM Database Vers +ion"; Win32::GUI::MessageBox($W1,$about_text,$about,64,); } ################# sub Exit1_Click { ################# return -1; #-- stops the event handler and exits } ####################### sub Window1_Terminate { ####################### return -1; #-- stops the event handler and exits } #################### sub Window1_Resize { #################### my $width = $W1->ScaleWidth(); my $height = $W1->ScaleHeight(); $TV->Resize(180,$height-10); $RE->Resize($width-205,$height-10); } ##### END { ##### CloseHandle($hFILE); untie(%BibleIDX); close(BibleRTF); Win32::GUI::Show($DOS); return -1; #-- stops the event handler and exits }

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1121222]
Approved by ww
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (4)
As of 2018-11-20 23:42 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    My code is most likely broken because:
















    Results (234 votes). Check out past polls.

    Notices?