Version 8 of Bob Clark

Updated 2003-04-11 20:08:25

Email [email protected] - the web site is currently at an advanced stage of unreadiness.

Living in the most beautiful part of the UK (opinions vary): Dedham Vale, Suffolk [L1 ], with Sue (libraries) and sometimes student offspring Sam (digital cinema) [L2 ] and Jo (TV and radio production).

Programming since 1970 {![clock seconds]!}, still not rich nor famous, but no plans to stop. Tcl user since 7.6, no plans to stop that either. Serious long-term lurker at this wiki, the best resource a language could have - thanks to all for all the free help.

Currently (May 2002) working as a freelancer for British Telecommunications Laboratories, Martlesham Heath on Intelligent Networks [L3 ], and for the British Home Office on monitoring Rehabilitation Programmes [L4 ] - you have to have at least two jobs in the UK these days.

Mainly trying to continue working in Oracle SQL, C, C++, Tcl/Tk and (whimper it) VB, mainly succeeding so far. Worrying about not knowing any of the above properly, nor Java, Perl, Python, Ruby, Scheme, C#, .Net... even slightly, yet. Always happy to be paid to learn though :)

Claiming one minuscule right to Tcl fame, having invented ClarifyScript, a C++ bolt-on for Tcl to let it talk to a Clarify (oops, now Nortel, oops, now Amdocs [L5 ]) object database - the audience is currently three projects and a few hundred users at BT, who have kindly offered to allow it to be public, although I don't believe there will be too many takers.

Now also claiming proud authorship of a 10-line Tcl program to set your PC's clock from an NTP server: see the TIME Protocol Client [L6 ] elsewhere in this wiki.

Reminiscing for a moment: anyone involved with Acorn BBC Micro home computing (6502@2MHz) in the early 1980s may remember me as one quarter of SoftMachinery, fabulous furry Prestel pioneers when bits went 75 per second in one direction and 1200 in the other. Prestel was a quite brilliant precursor of the web, invented by Sam Fedida at BT Labs when BT was still the Post Office [L7 ], and completely eclipsed as soon as HTTP arrived.

But we did get to be Essex MUD wizards [L8 ] along the way, digital journalists at the gnotorious Home Of The Gnome (*258192# - error: no carrier), and invented a few quite amazing things that never made any money at all. One of the partners' previous companies was called Belder, which in hindsight probably explains a lot. Oh, and we invented Danny O'Brien too [L9 ].

Scattered to the winds in the 90s by recession and the rising price of Nike trainers, pursuing rather more conventional employment these days, although none of us has stopped inventing so far as I can tell.


ClarifyScript

This will only make any sense to dedicated Clarifiers (if them :). Possibly this could be a model for other object database packages, but really, SQL is still the best way to access a database. ClarifyScript is a shell for the Clarify Low-Level C API (LLAPI).

 proc SubcaseStateTransition {id_number newstate} {
 #### sets subcase state to newstate (a valid Open global string) with all the trimmings
 global env
     transaction {
         set now [sysdate]
         set subcase [find subcase id_number $id_number]         ;# default [find the ...] for exactly one object, or error
         set user [find user login_name $env(CLARIFY_USER1)]     ;# current user's login_name
         set oldstatus [find via $subcase subc_casests2gbst_elm] ;# follow a relation to find current status string object
         set newstatus [find string Open $newstate]              ;# find the global string $newstatus in the "Open" global list
         set transit "from status [$oldstatus get title] to status [$newstatus get title]"    ;# informative message
         $subcase set subc_casests2gbst_elm $newstatus           ;# relate the subcase to its new status string object
         transaction {                                           ;# a separate transaction is necessary here
             set chgst [find string "Activity Name" "Chg Status"];# another global string, from the "Activity Name" list
             set user2 [find user objid [$user get objid]]       ;# must re-find these objects because there is ... 
             set subc2 [find subcase objid [$subcase get objid]] ;# ... no relating between transactions (LLAPI issue)
             set actent [find new act_entry]                     ;# [find new ...] to create a new act_entry object
             $actent set act_code            300                 \
                         entry_time          $now                \
                         addnl_info          $transit            \
                         proxy               $env(CLARIFY_USER1) \
                         entry_name2gbst_elm $chgst              \
                         act_entry2user      $user2              \
                         act_entry2subcase   $subc2
             commit                                              ;# commit in inner transaction to establish new objid
             set aeobjid [$actent get objid]                     ;# remember objid, because all objects [found] in this ...
         }                                                       ;# ... transaction are discarded when it ends (LLAPI issue)
         set actent [find act_entry objid $aeobjid]              ;# re-find the new act_entry using its objid
         set stchg [find new status_chg]                         ;# create and populate a new status_chg object
         $stchg set  creation_time         $now                  \
                     notes                 $transit              \
                     status_chg2act_entry  $actent               \
                     subc_stat_chg2subcase $subcase              \
                     c_status_chg2gbst_elm $newstatus            \
                     p_status_chg2gbst_elm $oldstatus            \
                     status_chger2user     $user
         set timeb [find new time_bomb]                          ;# and all because time_bomb has objid pointers not relations :(
         $timeb set  end_time              $now                  \
                     focus_lowid           [$subcase get objid]  \
                     focus_type            24                    \
                     time_period           [$actent get objid]   \
                     flags                 65538                 \
                     left_repeat           0                     \
                     cmit_creator2employee $user
         commit                                                  ;# commit in outer transaction to update the database
         if {$env(CLARIFYSCRIPT_DEBUG)} {                        ;# notifier example
             $user notify "DEBUG: SubcaseStateTransition $id_number: $transit"
             commit
         }
     }                                                           ;# discard outer transaction and object memory
 }

The [find ...] command locates zero, one or more Clarify objects in the database as a named set, and creates a new Tcl command setname through which to access that set, in classic Tcl style, using subcommands to control the type of query, and trailing field name and value pairs to filter the results (always ANDed).

[find] always creates a new setname command accessing a set of zero, one or more Clarify objects, always all of the same objtype, always distinct with no duplicates, and [find] always returns the name of the new command setname, or fails with an error. A -sort option allows the object set to be pre-sorted in the database before being fetched.

[find ?the? objtype ?field value ...?] finds a set of exactly one object by field lookup, or fails.

[find every objtype ?field value ...?] finds a set of zero, one or more objects by field lookup.

[find new objtype ?field value ...?] creates a new Clarify object, or optionally finds exactly one existing object with matching field values, or creates and sets field values if none found, or fails if many found.

[find index setname index] isolates a set of one object from another set of one or more by index number, or fails if index out of range 0..[setname count]-1.

[find via setname relation ?field value ...?] follows a relation from a set of one object, to a set of zero, one or more objects, optionally also filtered by field values.

[find string listtitle stringtitle] finds a Clarify global string object from a global list object by their titles, as a set of one object.

[find union setname setname1 ?...?], [find minus setname setname1 ?...?] and [find intersect setname setname1 ?...?] perform standard set operations pretty fast (using Tcl hash tables), resulting in a set of zero, one or more objects.

[find empty objtype] returns an empty set, nominally of objtype.

Having [found] a set of Clarify objects, use its setname command to manipulate it:

[setname count] returns the number of objects in setname.

[setname objtype] returns the objtype of the objects in setname, had you forgotten.

[setname foreach var script] iterates through setname, via a set of one object at a time, whose command name is placed in var each time script is evaluated.

[setname get field ?...?] gets a list of field values, from a set of exactly one object.

[setname list field ?...?] gets a list of a list of field values, from a set of zero, one or more objects - there is one outer list element per object or row, one inner list element per field value.

[setname report field ?...?] gets a list of a list of field values, from a set of zero, one or more objects, then returns the results padded into aligned rows and columns.

[setname set field value ?...?] sets fields or relations, in a set of one or more objects.

[setname delete] deletes a set of one or more objects from the database.

[setname in othersetname], [setname has othersetname], [setname is othersetname] do fast set comparisons (using Tcl hash tables) - [setname has ...] also recognises none|one|some|many as meaningful othersetnames representing 0|1|>=1|>1 objects of the appropriate objtype.

Get, list, report and set include syntax to get or set fields in related objects on the fly, and list and report have a -sort option for Tcl-based post-fetch sorting.

[caseorsubcasesetname log string] correctly adds an entry to case or subcase objects' history log.

[usersetname notify string ?...?] uses the Clarify Notifier subsystem to notify users of an event, or can call a Clarify Basic procedure in an online users' GUI.

[sysdate ...] gets the time now in Clarify datestring style, or converts between Clarify datestring and Tcl [clock seconds].

[transaction], [commit ...] and [rollback] are for optional transaction and object memory management, otherwise a default transaction is provided which must be committed to update the database.

For memory management, each setname belongs to the transaction in which it was created, and the command and its object set memory are discarded when that transaction ends or is rolled back. Explicit transactions are seldom but occasionally required, as in the sample above.

ClarifyScript is about 4 years old, currently an untidy but reliable pile of Sun Forte 4.2 vintage C++ classes, linked with Tcl 8.3 and the Clarify High- and Low-Level APIs up to 10.1, running on Solaris up to 8, and definitely not a standard Tcl plug-in package in any way at all.

There is an executable ClarifyScript Shell cssh, and three classes to allow embedded ClarifyScript in C++ programs.

It has so far only been used with Clarify ClearSupport, buts looks ready for the other Clarify applications.

ClarifyScript is database-independent, because it is based on the Clarify APIs, although we have only used it with Oracle (up to 8.1.7.3), and in fact currently build Oratcl into it too - thanks guys, it's good to be able to drop into SQL when the devil drives.

ClarifyScript was written while Tcl 8.0 was still in alpha, so it uses the Ousterhout 7.6 string-based internal model.

There is a manual.


Category Person