NAME

ODBC::Ext.pm - Extentions to the ODBC module

ABSTRACT

This module permits the modification and addition of data in ODBC tables. It also includes more conginial searching functions.

SECTIONS

ABSTRACT -- SECTIONS -- DESCRIPTION -- BIGER EXAMPLE -- INSTALLATION -- AVAILABILITY -- BUGS!@#! -- AUTHORS

DESCRIPTION

(more like a history, but what the hey -:)

After looking over the excelent Win32::ODBC module, I realised that it's oriented towards data retrieval. This, if you ask me, is only half (or even a third) of what one usualy does with databases. The basic ODBC functions (in ODBC.pll) didn't include any functions to modify the data either. I can well understand their lack, I can't make head or tail of the SqlBind functions either. So I decided to write some wrapers around the SQL INSERT and UPDATE statements. I also thought it would be useful to have simpler searching functions and maybe even be able to use Perl regexs for searching.

Of course, this is only an extention to the old Win32::ODBC package. All the old functions that we all know and love are still available.

VARIABLES

$newline Static
This variable is appended to each element of an array and each hash key: value pair when it is used by the PrepVal method. It is currently defined as '%0D%0A'. You could change this to '<p>' if the data is only going to be used on the web, or anything else that suits your fancy.

METHODS

List

Abort -- Append -- DeprepVal -- Edit -- FindFirst -- FindFirstX -- FindNext -- Found -- Get -- PrepVal -- Set -- Table -- Update -- new

new ODBC::Ext (['DSNname'])
Creates a ODBC::Ext object and opens a connection to the DSN name given. If an error occurs (say the DSN doesn't exist), new returns a string that starts with 'Error: ' followed by an error message.

        $odbc = new ODBC::Ext ('Enviro');
        if($odbc =~ /^Error:/)
        {
            die "Connecting to 'Enviro', $odbc";
        }
Get ('field')
Returns the value of the given field in the current record. Sql, FindFirst , FindFirstX or Edit should be called first to select the record.

Note: because I use an SQL statement to modify values, some of them must be encoded. The Get method therefore decodes everything with DeprepVal . See Edit for an explanation.

        $odbc->Sql("SELECT ID_nom, ID_tele, ID_fax FROM Chercheur"
                   ." WHERE (ID_nom='Jean Drolet'");
        print $odbc->Get('ID_nom')."\n";
        print $odbc->Get('ID_tele')."\n";
        print $odbc->Get('ID_fax')."\n";
Set ('field', $value)
Set the value of the current field to a new value. The changes aren't writen to disk until the Update method is called.

Note: SQL does not permit single quotes (') in a statement (or if it does, I don't know how). THIS IS VERY ANNOYING! Nor does it permit exotic characters such as newlines and what not. Ticks (') are encoded as %27 (ie % followed by the ascii value in hex). You will need to translate back anything at the other end ( Get does this automaticaly).

Another thing to watch out for is date values. Make sure they are in cannonical form, because 1/3/1995 can be ambiguous.

        $personne{'addr'}=['that number','this street','some city'];
        $data->Append();
        $data->Set('ID_nom', $personne{'nom'});
        $data->Set('ID_addr', $data->PrepVal($personne{'addr'}));
        $data->Set('ID_tele', $personne{'tele'});
        $data->Set('ID_fax', $personne{'fax'});
        $data->Set('ID_e_mail', $personne{'e_mail'});
        $data->Update();
Edit (['table'])
Prepares the current record for modification. The Get and Set methods may then be used to modify the record. Changes are only writen to the table when the Update method is called. If the table isn't specified, the current table is used. Be aware of that Edit has some wonky behaviour. See BUGS!@#! .

        $odbc->Sql("SELECT * FROM Invoice WHERE ID='00101'")
        $odbc->Edit('Invoice');
        $odbc->Set('Status', 'done');
        $odbc->Update();
Append (['table'])
Creates a new record. The Set method should then be used to specify the data in this record. However, it is only writen to the table when the Update method is called. If the table isn't specified, the current table is used.

        $odbc->Append('Records');
        $odbc->Set('Artist', "Engelberg Humperdinkt");
        $odbc->Set('Record', "The yodel trance");
        $odbc->Update();
Abort ()
Kills the current Edit or Append . While calling this is STRICTLY nesecairy, one should to preserve sanity (because you might call Update later) and to clean up.

Update ()
Flushes any temporary data to the active table. This adds a record if Append was called before, or modifies the record if Edit was called. Be aware of the wonky Edit behaviour. See BUGS!@#! .

DeprepVal ($scalar)
Converts any escaped values to there original form. ie %27 becomes '. This function is automaticaly called by the Get method, so you probably don't need it.

PrepVal ($ref)
Prepares a value for use with the Set method. Arrays are joined together, seperated by the $newline class variable to form a string. Hashes under go a similar treatement, except each line is made up of 'key: value'. Prepval also excapes any caracters that can't be handled in an SQL statement. Read the perlref man page if you're not an expert on references.

        $hello=$odbc->PrepVal(\@array);
        $odbc->Set('Memo_field', $hello);
Table (['table'])
Sets the current table to be used by future calls to Append , Edit , FindFirst and FindFirstX . It should NOT be called during an Append or Edit operation. It can also be used to read the current table.

        print "We are accessing ".$odbc->Table();
FindFirst (['clause'], ['table'])
Find the first record for a given search clause. The current active table is used if none is given. The search clause is any valid SQL WHERE clause. I am far from being a SQL expert, so I can't really enumerate them all here. To find out if a record was found, call Found . To proced to the next record in the search, call FindNext . If the clause is not given all records will be selected. This is useful for steping through the entire table.

        $odbc->Sql("SELECT * FROM Comp_Books")  # see wonky Edit() bug
        $odbc->FindFirst('YEAR(start_date) IN (1991, 1992)', 'Comp_Books');
        while($odbc->Found())
        {
            $odbc->Edit();
            print $odbc->Set('Obsolete', 'Very!');
            $odbc->Update();
            $odbc->FindNext();
        }
FindFirstX ($sub_clause, ['table'])
This is similar to the FindFirst method, except a Perl subroutine is used to validate each record to see if it should be included in the search. The subroutine is passed a single parameter: a hash that has all the field names as keys and their data as values. To find out if a record was found, call Found . To proced to the next record in the search, call FindNext .

I included this mainly so one could do some regex comparisons.

        $harold=sub    # Note no sub name!  Read perlref for an explanation
            {   local(%data)=@_;
                return ($data{'name'}=~/harold/i);
            }
        $odbc->FindFirst($harold, 'Kings_of_England');
        while($odbc->Found())
        {
            print $odbc->Get('name')."\n";
            print $odbc->Get('death')."\n";
            print $odbc->Get('major_wars')."\n";
            $odbc->FindNext();
        }
FindNext ()
Proceed to the next record in the current search. Searchs are instigated by FindFirst and FindFirstX . See those methods for examples.

Found ()
This method revels wether there is currently a record available in the current search. See FindFirst or FindFirstX for examples.

BIGER EXAMPLE

        require ODBC::Ext;
        $odbc= new ODBC::Ext("Monarchs");
        $odbc->Append("Kings");
        $odbc->Set('name', 'dread fil');
        #    $odbc->Set('death', 'I'm not dead yet!');
        @feats=('Wrote some good CGIs in under 2 hours',
                'Learned more than 7 programing languages',
                'Played decent guitar',
                'Made a profit on self produced educational game',
                'Hitch-hiked across Canada (twice)',
                'Learned 3 human languages',
                'Became frightfuly witty and modest',
               );
        $odbc->Set('noted_actions', $odbc->PrepVal(\@feats));
        $odbc->Update();
        $odbc->Append("Queens");
        $odbc->Set('name', 'George the Beautious');
        $odbc->Set('death', '14/10/1969');
        @feets=('Charter member of the Entobicok LASM',
                'Never broke a heel',
                'Only beat up twice by those THRICE DAMNED gay bashers',
                'Learned not to tell construction workers not to F*** off',
                'Convinced mother to change nail polish'
                'NEVER appeared on Oprah'
               );
        $odbc->Set('noted_actions', $odbc->PrepVal(\@feets));
        $odbc->Abort();                     # this example is getting TO SILLY!!!
        $odbc->FindFirst('YEAR('death') < 1990');
        while($odbc->Found())
        {
            print 'Here's another moldy one: ', $odbc->Get('name'), "\n";
            $odbc->FindNext();
        }
        # this next example is brought to you by the letters M, L and silent-Q
        $sponsor=sub
            {   local(%data)=@;
                return ($data{'name'}=~/[ML]|(silent-Q)/);
            }
        $odbc->FindFirstX($sponsor, 'Kings, Queens');
        while($odbc->Found())
        {
            print 'Three cheers for ', $odbc->Get('name'), "\n";
            $odbc->FindNext();
        }

INSTALLATION

Copy the file Ext.pm to perl-lib-dir\Win32\ODBC\Ext.pm and away you go, simple as that.

AVAILABILITY

I'll put it at http://www.interlinx.qc.ca/~fil/Perl, for now. Eventualy I hope to have it in CPAN.

BUGS!@#!

Wonky Edit behaviour.
Ok, there's no hiding it: I'm an SQL neophyte. And I just could get enough information to understand how to use cursors in SQL. Sigh. This means the Update method uses a WHERE clause to define which record should be modified. The WHERE clause is defined by all the data in all the fields currently selected. This could very well be insufficiant to uniquely select the desired record. So you could very well end up modifing more than one record.

To work around this bit of sloppy coding, make sure you have enough fields selected to uniquely define the record. A Sql('SELECT * FROM George'); usualy does the trick. It should be noted that if your table has totaly identical records, they will both be modified, no matter what. But then, databases as a rule shouldn't included such cases.

Of course, you may wish to make use of this feature, but I can't garanty that it will stick around. -:)

DataHash If you bi-pass Get , values will not be decoded. See Edit .
Other
Other bugs? YES! Probably many. This code might interact in strange ways with the Win32::ODBC package. Your kilometerage may vary. When in doubt test test test! and use the source! I knocked this up in an afternoon (in fact, this documentation is taking longer to write -:) and don't have the time (nor the inclanation) to extensively debug it. But then, Perl is a very forgiving language, which is what I ADORE about it. Long live Larry!

If you find anything out of order, or have comments or sugestions, please by all means send them to me. But don't expect me to drop everything to fix a bug.

AUTHORS

Just lil' old me, so far. -:) Philip Gwyn fil@interlinx.qc.ca

DISCLAIMER

This software is provided AS IS, without any warranty, neither explicit nor implied as to it's suitablilty to any given task. If you crash and burn because of this software, that's your own look out.